Сколько аргументов можно передать в функцию python
Перейти к содержимому

Сколько аргументов можно передать в функцию python

  • автор:

Функции¶

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

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

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

В Python функции можно разделить на три типа:

  • встроенные (список built-in функций);
  • именованные (определенные пользователем при помощи def );
  • анонимные ( lambda -функции).

Все функции являются объектами типа function .

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

  • print() – вывод данных на экран;
  • str() – создание объектов строкового типа;
  • type() – определение типа объекта.

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

После разбора лекции советуем открыть документацию print() , например, и разобраться с подробностями работы.

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

Пример¶

Представим, что необходимо находить количество корней квадратного уравнения — это легко можно реализовать на Python!

Именованные функции¶

Определение¶

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

В Python существует особый синтаксис определения именованных функций:

    в начале — ключевое слово def ;

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

правила:

  • название не может начинаться с числа;
  • можно использовать нижнее подчеркивание _ , цифры и буквы;

рекомендации:

  • snake_case : в названии только буквы нижнего регистра, слова разделяются _ ;
  • название функции должно быть уникальным;

круглые скобки и, опционально, параметры внутри (о них ниже);

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

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

Вызов¶

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

Возвращаемое значение¶

Все функции в Python имеют одно и только одно возвращаемое значение. Если в теле функции отсутствует ключевое слово return , возвращаемое значение всегда будет None .

Возможно ли вернуть несколько значений?

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

  • список (например, [1, 2, 3] )
  • кортеж ( (1, 2, 3) )
  • словарь ( <"key_one": 1, "key_two": 2, "key_three": 3>)
  • объект класса (см. раздел объекты и классы)

Таким образом, возвращается одно значение, а содержать в себе оно может несколько других.

Возвращение значения означает, что его можно использовать вне функции, например, присвоить полученное значение переменной. Давайте посмотрим, что возвращает print_theme() и add_two() :

Как видите, несмотря на отсутствие return в коде функции, она действительно возвращает None .

Теперь посмотрим на add_two() , где возвращаемое значение задано нами:

Множественные return -ы¶

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

Покажем это на примере функции, умножающей нечетные числа на 2 и делящей четные числа пополам.

Выражение в строке 3 будет выполнено в случае, если выполняется условие из строки 2. При этом происходит выход из функции, и следующие выражения в ее теле уже не исполнятся при этом вызове. Поэтому нет необходимости писать else :

Функция change_num_2 эквивалентна change_num , но содержит лишний уровень вложенности. Знание о том, что после первого return происходит выход из функции, позволяет избежать лишней вложенности.

Пространства имен и области видимости¶

Чуть выше была определена add_two() , внутри которой инициализировалась переменная result . Значение этой переменной нельзя получить, обратившись к ней вне функции.

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

В Python объектам можно давать имя и обращаться к ним по нему. Эти имена организованы в пространства имен или namespace. Инициализация переменной добавляет в namespace название объекта. Namespace — набор имен определенных на текущий момент объектов. Представьте себе dict , где ключом является строка, а значением — ссылка на объект. Область видимости определяет, переменные из каких пространств имен сейчас доступны. Разберем, как и где Python ищет объекты, к которым обращаются (этот процесс называется name resolution).

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

  • локальные (Local) — локальные переменные функции, данная область существует до тех пор, пока функция не завершит работу после вызова;
  • локальные пространства могут быть вложены друг в друга, в таком случае область уровня \(N\) (Enclosing) содержит «более глубокую» \(N + 1\) . Поиск имени, вызванного на уровне \(N\) , начинается с локального namespace этого уровня и продвигается «наружу», то есть на уровни выше;
  • глобальные (Global) — все объекты, определенные на уровне скрипта;
  • встроенные (Built-in) — namespace содержит все встроенные объекты (функции, исключения и т. д.), поиск в нем осуществляется последним.

Если имя не было найдено даже на уровне Built-in, будет выброшено исключение NameError .

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

Замыкания¶

Замыкание (Closure) — это функция, объявленная в теле внешней функции, и использующая значения из области видимости внешней функции.

Замыкания удобно использовать для динамического создания функций.

Каррирование¶

Каррирование (Currying) — это превращение функции от нескольких аргументов в последовательность функций от одного аргумента.

В Python реализован менее строгий аналог каррирования. С помощью функции partial можно получить функцию от меньшего числа аргументов, но не обязательно одного. Рассмотрим пример.

Первым аргументом в partial передается функция. А далее через запятую можно передать от \(0\) до \(N\) аргументов, которые требуется зафиксировать, где \(N\) — это число аргументов исходной функции. Возвращаемое значение partial — это функция от \(N — x\) аргументов, где \(x\) — это число аргументов, переданных в partial (и таким образом зафиксированных). Передавать в partial только функцию и \(0\) аргументов можно, но не имеет смысла (получится функция от \(N\) аргументов, которая и была изначально). Если же зафиксировать все \(N\) аргументов, то на выходе получится функция от нуля аргументов (если это была чистая функция, результат будет эквивалентен константе).

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

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

Чистые функции¶

Чистой функцией (pure function) называют функцию, одновременно обладающую следующими свойствами:

  • является детерминированной;
  • не имеет побочных эффектов.

Детерминированность означает, что возвращаемое значение всегда одинаково для одних и тех же значений аргументов.

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

  1. 4
  2. 4
  3. 6
  4. 4

Функция fn1 не имеет побочных эффектов, но она не детерминирована потому что зависит от external_dict . Поэтому она не чистая.

Функция fn2 детерминирована, но она имеет побочный эффект — изменяет содержимое external_dict . Поэтому она не чистая.

Функция fn3 детерминирована и не имеет побочных эффектов, поэтому она чистая.

Функция print тоже была вызвана. Является ли она чистой? Вывод на печать — это побочный эффект, поэтому нет.

Вызов fn2 изменил содержимое external_dict , поэтому второй вызов fn1 дал результат, отличный от первого вызова.

Подумайте, какие значения будут напечатаны?

Ответ можно посмотреть нажав на + справа возле print

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

Параметры¶

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

Для начала немного формализма:

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

То есть происходит отображение: аргументы, с которыми вызывается функция \(\Rightarrow\) значения параметров.

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

Позиционные параметры¶

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

Данный тип параметров характеризуется следующим:

  • идут первыми после открытых скобок, все именованные строго после них;
  • важен порядок: отображение аргументов в параметры будет последовательным;
  • при вызове функции все аргументы, которые ожидает функция, должны быть переданы (иначе откуда Python возьмет значения? вот именно!)

Разберем пример, который суммирует два числа:

А что, если количество входных переменных очень большое или вы заранее не знаете, сколько аргументов будет передано при вызове? Например, вам нужно сложить не 2 числа, а 102? В Python есть специальный синтаксис со звездочками. После позиционных аргументов можно указать list , элементами которого станут неограниченное количество переданных позиционных аргументов.

Синтаксис: имя_функции([поз_0, . поз_N,] [*поз_список]): . ; [] в данном случае обозначают необязательность.

Лучше передавать все в списках или векторах (о которых будет позже)

Именованные параметры¶

Данные параметры имеют значения по умолчанию.

Синтаксис: имя_функции([поз_0, . поз_N,] [*поз_список], [им_0=значение_0, . им_K=значение_K], [**им_словарь]): .

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

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

Что это за комментарий в тройных кавычках внутри функции?

Это один из общепринятых способов написания docstring — документации по функции.

Списки как значения по умолчанию¶

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

Второй вызов функции привел к результату, отличающемуся от первого вызова. Почему так произошло? Значение ls по умолчанию мы объявили равным [1] . Оба вызова используют значение по умолчанию. Но при втором вызове в данном случае произошло обращение к тому же списку, который был создан в качестве значения по умолчанию при первом вызове. Как это можно проверить?

В Python определена встроенная функция id. Она возвращает целочисленный идентификатор объекта (уникальный и постоянный, пока объект существует). Используем ее, чтобы посмотреть идентификаторы списков.

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

Одним из решений может быть следующее:

Обратите внимание, что с set -ом ситуация другая.

Анонимные функции¶

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

В определении выражение — это возвращаемое значение анонимной функции, например:

В примере выше lambda -функции были только созданы в моменте, но не вызваны. Можно сказать, что мы их определили (как с def ), но не воспользовались и сразу потеряли к ним доступ.

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

В отличии от именованной, анонимная функция может иметь только одно выражение.

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

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

А вот пример с отложенными вычислениями:

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

Декораторы¶

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

Пример¶

Выше была определена функция many_arg_sum() , давайте засекать, сколько она работает:

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

Использование синтаксического сахара с @ и указанием имени декоратора над функцией аналогично вызову

Генераторы¶

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

Вот простейший пример функции-генератора:

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

Инструкция yield ¶

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

Ниже представлены две функции (генерируют последовательность в обратном порядке), одна с оператором return , а другая функция-генератор с оператором yield . Принимают на вход некое значение n , в примере выше — 5 , и возвращают последовательность чисел от 4 до 0 .

Функция get_subsequence возвращает последовательность в виде списка. Такая функция хранит промежуточное состояние своей работы в виде списка. В примере выше такое состояние хранится в списке result , который и будет возвращён после окончания работы цикла while с помощью оператора return . Список будет возвращён в то место, откуда произошёл вызов функции, при этом важно понимать, что оператор return возвращает не только результат работы функции, но и управление ходом выполнения программы в то место, в котором был произведён вызов функции get_subsequence . При повторном вызове функции get_subsequence генерация чисел происходит заново.

Генератор generate_subsequence на первый взгляд делает тоже самое, генерирует последовательность чисел в обратном порядке, только он такую и происходит это благодаря оператору yield , который не возвращает контроль над ходом выполнения программы в то место, в котором был произведён вызов функции-генератора, а передаёт контроль на время. Для того, чтобы очередной сгенерированный функцией-генератором необходимо использовать встроенную функцию next , таким образом исполнение функции на время приостанавливается, до тех пор, пока снова не будет использована функция next . Локальная переменная внутри генератора неявным образом сохраняет своё состояние.

Eсли генератор вернёт все значения из сгенерированной последовательности и если будет выполнено ещё одно обращение к объекту генератора gen с помощью функции next — будет возвращено исключение StopIteration , как видно на 13-й строке примера выше. Генератор не смог вернуть ещё одно значение поскольку больше таких значений не осталось в сгенерированной последовательности.

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

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

Python args and kwargs: Demystified

Sometimes, when you look at a function definition in Python, you might see that it takes two strange arguments: *args and **kwargs . If you’ve ever wondered what these peculiar variables are, or why your IDE defines them in main() , then this article is for you. You’ll learn how to use args and kwargs in Python to add more flexibility to your functions.

By the end of the article, you’ll know:

  • What *args and **kwargs actually mean
  • How to use *args and **kwargs in function definitions
  • How to use a single asterisk ( * ) to unpack iterables
  • How to use two asterisks ( ** ) to unpack dictionaries

This article assumes that you already know how to define Python functions and work with lists and dictionaries.

Free Bonus: Click here to get a Python Cheat Sheet and learn the basics of Python 3, like working with data types, dictionaries, lists, and Python functions.

Passing Multiple Arguments to a Function

*args and **kwargs allow you to pass multiple arguments or keyword arguments to a function. Consider the following example. This is a simple function that takes two arguments and returns their sum:

This function works fine, but it’s limited to only two arguments. What if you need to sum a varying number of arguments, where the specific number of arguments passed is only determined at runtime? Wouldn’t it be great to create a function that could sum all the integers passed to it, no matter how many there are?

Using the Python args Variable in Function Definitions

There are a few ways you can pass a varying number of arguments to a function. The first way is often the most intuitive for people that have experience with collections. You simply pass a list or a set of all the arguments to your function. So for my_sum() , you could pass a list of all the integers you need to add:

This implementation works, but whenever you call this function you’ll also need to create a list of arguments to pass to it. This can be inconvenient, especially if you don’t know up front all the values that should go into the list.

This is where *args can be really useful, because it allows you to pass a varying number of positional arguments. Take the following example:

In this example, you’re no longer passing a list to my_sum() . Instead, you’re passing three different positional arguments. my_sum() takes all the parameters that are provided in the input and packs them all into a single iterable object named args .

Note that args is just a name. You’re not required to use the name args . You can choose any name that you prefer, such as integers :

The function still works, even if you pass the iterable object as integers instead of args . All that matters here is that you use the unpacking operator ( * ).

Bear in mind that the iterable object you’ll get using the unpacking operator * is not a list but a tuple . A tuple is similar to a list in that they both support slicing and iteration. However, tuples are very different in at least one aspect: lists are mutable, while tuples are not. To test this, run the following code. This script tries to change a value of a list:

The value located at the very first index of the list should be updated to 9 . If you execute this script, you will see that the list indeed gets modified:

The first value is no longer 0 , but the updated value 9 . Now, try to do the same with a tuple:

Here, you see the same values, except they’re held together as a tuple. If you try to execute this script, you will see that the Python interpreter returns an error:

This is because a tuple is an immutable object, and its values cannot be changed after assignment. Keep this in mind when you’re working with tuples and *args .

Using the Python kwargs Variable in Function Definitions

Okay, now you’ve understood what *args is for, but what about **kwargs ? **kwargs works just like *args , but instead of accepting positional arguments it accepts keyword (or named) arguments. Take the following example:

When you execute the script above, concatenate() will iterate through the Python kwargs dictionary and concatenate all the values it finds:

Like args , kwargs is just a name that can be changed to whatever you want. Again, what is important here is the use of the unpacking operator ( ** ).

So, the previous example could be written like this:

Note that in the example above the iterable object is a standard dict . If you iterate over the dictionary and want to return its values, like in the example shown, then you must use .values() .

In fact, if you forget to use this method, you will find yourself iterating through the keys of your Python kwargs dictionary instead, like in the following example:

Now, if you try to execute this example, you’ll notice the following output:

As you can see, if you don’t specify .values() , your function will iterate over the keys of your Python kwargs dictionary, returning the wrong result.

Ordering Arguments in a Function

Now that you have learned what *args and **kwargs are for, you are ready to start writing functions that take a varying number of input arguments. But what if you want to create a function that takes a changeable number of both positional and named arguments?

In this case, you have to bear in mind that order counts. Just as non-default arguments have to precede default arguments, so *args must come before **kwargs .

To recap, the correct order for your parameters is:

  1. Standard arguments
  2. *args arguments
  3. **kwargs arguments

For example, this function definition is correct:

The *args variable is appropriately listed before **kwargs . But what if you try to modify the order of the arguments? For example, consider the following function:

Now, **kwargs comes before *args in the function definition. If you try to run this example, you’ll receive an error from the interpreter:

In this case, since *args comes after **kwargs , the Python interpreter throws a SyntaxError .

Unpacking With the Asterisk Operators: * & **

You are now able to use *args and **kwargs to define Python functions that take a varying number of input arguments. Let’s go a little deeper to understand something more about the unpacking operators.

The single and double asterisk unpacking operators were introduced in Python 2. As of the 3.5 release, they have become even more powerful, thanks to PEP 448. In short, the unpacking operators are operators that unpack the values from iterable objects in Python. The single asterisk operator * can be used on any iterable that Python provides, while the double asterisk operator ** can only be used on dictionaries.

Let’s start with an example:

This code defines a list and then prints it to the standard output:

Note how the list is printed, along with the corresponding brackets and commas.

Now, try to prepend the unpacking operator * to the name of your list:

Here, the * operator tells print() to unpack the list first.

In this case, the output is no longer the list itself, but rather the content of the list:

Can you see the difference between this execution and the one from print_list.py ? Instead of a list, print() has taken three separate arguments as the input.

Another thing you’ll notice is that in print_unpacked_list.py , you used the unpacking operator * to call a function, instead of in a function definition. In this case, print() takes all the items of a list as though they were single arguments.

You can also use this method to call your own functions, but if your function requires a specific number of arguments, then the iterable you unpack must have the same number of arguments.

To test this behavior, consider this script:

Here, my_sum() explicitly states that a , b , and c are required arguments.

If you run this script, you’ll get the sum of the three numbers in my_list :

The 3 elements in my_list match up perfectly with the required arguments in my_sum() .

Now look at the following script, where my_list has 4 arguments instead of 3:

In this example, my_sum() still expects just three arguments, but the * operator gets 4 items from the list. If you try to execute this script, you’ll see that the Python interpreter is unable to run it:

When you use the * operator to unpack a list and pass arguments to a function, it’s exactly as though you’re passing every single argument alone. This means that you can use multiple unpacking operators to get values from several lists and pass them all to a single function.

To test this behavior, consider the following example:

If you run this example, all three lists are unpacked. Each individual item is passed to my_sum() , resulting in the following output:

There are other convenient uses of the unpacking operator. For example, say you need to split a list into three different parts. The output should show the first value, the last value, and all the values in between. With the unpacking operator, you can do this in just one line of code:

In this example, my_list contains 6 items. The first variable is assigned to a , the last to c , and all other values are packed into a new list b . If you run the script, print() will show you that your three variables have the values you would expect:

Another interesting thing you can do with the unpacking operator * is to split the items of any iterable object. This could be very useful if you need to merge two lists, for instance:

The unpacking operator * is prepended to both my_first_list and my_second_list .

If you run this script, you’ll see that the result is a merged list:

You can even merge two different dictionaries by using the unpacking operator ** :

Here, the iterables to merge are my_first_dict and my_second_dict .

Executing this code outputs a merged dictionary:

Remember that the * operator works on any iterable object. It can also be used to unpack a string:

In Python, strings are iterable objects, so * will unpack it and place all individual values in a list a :

The previous example seems great, but when you work with these operators it’s important to keep in mind the seventh rule of The Zen of Python by Tim Peters: Readability counts.

To see why, consider the following example:

There’s the unpacking operator * , followed by a variable, a comma, and an assignment. That’s a lot packed into one line! In fact, this code is no different from the previous example. It just takes the string RealPython and assigns all the items to the new list a , thanks to the unpacking operator * .

The comma after the a does the trick. When you use the unpacking operator with variable assignment, Python requires that your resulting variable is either a list or a tuple. With the trailing comma, you have defined a tuple with only one named variable, a , which is the list [‘R’, ‘e’, ‘a’, ‘l’, ‘P’, ‘y’, ‘t’, ‘h’, ‘o’, ‘n’] .

Where's the tuple? Show/Hide

You never get to see the tuple that Python creates in this operation, because you use tuple unpacking in combination with the unpacking operator * .

If you name a second variable on the left-hand side of the assignment, Python will assign the last character of the string to the second variable, while collecting all remaining characters in the list a :

When you use this operation with a second named variable like shown above, the results might be more familiar, if you’ve worked with tuple unpacking before. However, if you want to unpack all items of the variable-length iterable into a single variable, a , then you need to add the comma ( , ) without naming a second variable. Python will then unpack all items into the first named variable, which is a list.

While this is a neat trick, many Pythonistas would not consider this code to be very readable. As such, it’s best to use these kinds of constructions sparingly.

Conclusion

You are now able to use *args and **kwargs to accept a changeable number of arguments in your functions. You have also learned something more about the unpacking operators.

  • What *args and **kwargs actually mean
  • How to use *args and **kwargs in function definitions
  • How to use a single asterisk ( * ) to unpack iterables
  • How to use two asterisks ( ** ) to unpack dictionaries

If you still have questions, don’t hesitate to reach out in the comments section below! To learn more about the use of the asterisks in Python, have a look at Trey Hunner’s article on the subject.

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Python args and kwargs: Demystified

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

About Davide Mastromatteo

Developer and editor of “the Python Corner". Blood donor, Apple user, Python and Swift addicted. NFL, Rugby and Chess lover. Constantly hungry and foolish.

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Aldren Santos

Geir Arne Hjelle

Jaya Zhané

Mike Driscoll

Master Real-World Python Skills With Unlimited Access to Real Python

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Master Real-World Python Skills
With Unlimited Access to Real Python

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

What Do You Think?

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal. Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session. Happy Pythoning!

# Python args and kwargs

Вы узнаете, как использовать **args и **kwargs в Python, чтобы повысить гибкость своих функций.

  • Что на самом деле означают *args и **kwargs
  • Как использовать *args и **kwargs в определениях функций
  • Как использовать одну звездочку (*) для распаковки итераций
  • Как использовать две звездочки (**) для распаковки словарей

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

# Передача нескольких аргументов в функцию

*args и **kwargs позволяют передавать функции несколько аргументов или ключевых слов. Рассмотрим следующий пример. Это простая функция, которая принимает два аргумента и возвращает их сумму:

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

# Использование переменной arg в определениях функций

Есть несколько способов передать переменное количество аргументов функции. Первый способ часто наиболее интуитивен для людей, имеющих опыт работы с коллекциями. Вы просто передаете список или набор всех аргументов в функцию. Таким образом, для get_sum() вы можете передать список всех целых чисел, которые нужно добавить:

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

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

В этом примере вы больше не передаете список get_sum() . Вместо этого вы передаете три разных позиционных аргумента. get_sum() берет все параметры, предоставленные во входных данных, и упаковывает их все в один повторяемый объект с именем args .

Обратите внимание, что args — это просто имя. Вы не обязаны использовать имя args . Вы можете выбрать любое имя, которое вы предпочитаете, например, integers :

Функция все еще работает, даже если вы передаете итерируемый объект как целые числа вместо аргументов. Здесь важно только то, что вы используете оператор распаковки (*) .

Имейте в виду, что итеративный объект, который вы получите с помощью оператора распаковки (*) , — это не список, а кортеж. Кортеж похож на список тем, что они поддерживают нарезку и итерацию. Однако кортежи сильно отличаются по крайней мере в одном аспекте: списки изменчивы, а кортежи — нет. Чтобы проверить это, запустите следующий код. Этот скрипт пытается изменить значение списка:

Значение, расположенное в самом первом индексе списка, должно быть обновлено до 9. Если вы выполните этот скрипт, вы увидите, что список действительно изменяется: первое значение больше не 0, а обновленное значение 9.

Теперь попробуйте сделать то же самое с кортежем:

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

Тип ошибки: объект 'tuple' не поддерживает назначение элемента Это потому, что кортеж является неизменным объектом, и его значения не могут быть изменены после присваивания. Имейте это в виду, когда вы работаете с кортежами и *args .

# Упражнения

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

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

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

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

# Использование переменной **kwargs в определениях функций

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

concatenate() будет перебирать словарь **kwargs и объединять все найденные значения:

Как и args , kwargs — это просто имя, которое можно изменить на любое, что вы захотите. Опять же, здесь важно использование оператора распаковки (**) .

Итак, предыдущий пример можно записать так:

Обратите внимание, что в приведенном выше примере повторяемый объект является стандартным dict . Если вы перебираете словарь и хотите вернуть его значения, как в показанном примере, тогда вы должны использовать .values​​() .

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

Если вы не указали .values​​() , функция будет перебирать ключи словаря kwargs , возвращая неверный результат.

# Упорядочивание аргументов в функции

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

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

Напомним, правильный порядок для ваших параметров:

  • *args аргументы,
  • **kwargs аргументы

Например, это определение функции является правильным:

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

Теперь **kwargs стоит перед *args в определении функции. Если вы попытаетесь запустить этот пример, вы получите сообщение об ошибке от переводчика:

В этом случае, поскольку *args идет после **kwargs , интерпретатор Python генерирует ошибку SyntaxError.

Функция с переменным количеством аргументов в Python: *args и **kwargs

python

В этой статье мы расскажем, зачем нужны *args и **kwargs в Python и как их использовать.

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

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

После запуска будет выведено sum: 35 .

Во фрагменте кода выше у нас есть функция adder() с тремя аргументами: x , y и z . При передаче трёх значений этой функции на выходе мы получаем их сумму. Но что, если передать больше трёх аргументов в эту функцию?

Из-за того, что здесь мы передаём 5 аргументов, при запуске программы выводится ошибка TypeError: adder() takes 3 positional arguments but 5 were given .

*args и **kwargs спешат на помощь

В Python можно передать переменное количество аргументов двумя способами:

  • *args для неименованных аргументов;
  • **kwargs для именованных аргументов.

Мы используем *args и **kwargs в качестве аргумента, когда заранее не известно, сколько значений мы хотим передать функции.

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

В результате выполнения программы мы получим следующий результат:

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

**kwargs

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

При запуске программы мы увидим следующее:

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

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

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