- Calling a Python function with *args,**kwargs and optional / default arguments
- 4 Answers 4
- Что такое args и kwargs в Python
- Зачем нам нужны * args и ** kwargs?
- Пример с * args
- Что это за тип * args и ** kwargs?
- Пример с ** kwargs
- Передача кортежа и словаря для сопоставления
- Когда использовать?
- Имитация ответа функции
- Функция декоратора
Calling a Python function with *args,**kwargs and optional / default arguments
So this would introduce some ambiguity as to whether 3 should be packed into args or kwargs . However, with Python 3, there is the ability to specify keyword only arguments:
def func(a,b,*,kw=None): # can be called as func(1,2), func(1,2,kw=3), but NOT func(1,2,3) .
def func(a,b,*args,*,kw1=None,**kwargs): .
However, this still brings up a syntax error (tested with Python3.2). Is there a reason for this that I am missing? And, is there a way to get the behavior I described above (Having *args with default arguments) — I know I can simulate that behavior by manipulating the kwargs dictionary inside the function.
@okm Because I didn’t test that version on python 3, only python 2. I just assumed the final version would work, and when It didn’t, I assumed the previous versions wouldn’t work either. Thanks!.
How should a bare 3 ever get into kwargs ? What keyword would it use? I cannot see any ambiguity. Note that the bare * in the argument list is only useful if there’s no *args . It’s a placeholder you use instead of *args .
Good question but why spreading the world-encompassing confusion of calling parameters (those guys in function definitions) arguments (those fellows in function calls)?
4 Answers 4
You can do that in Python 3.
def func(a,b,*args,kw1=None,**kwargs):
The bare * is only used when you want to specify keyword only arguments without accepting a variable number of positional arguments with *args . You don’t use two * s.
To quote from the grammar, in Python 2, you have
parameter_list ::= (defparameter ",")* ( "*" identifier [, "**" identifier] | "**" identifier | defparameter [","] )
parameter_list ::= (defparameter ",")* ( "*" [parameter] ("," defparameter)* [, "**" parameter] | "**" parameter | defparameter [","] )
which includes a provision for additional parameters after the * parameter.
Latest Python 3 documentation here.
*args should be after keyword arguments should it not? e.g. def func(a,b, kw1=None, *args, **kwargs):
@Nimi I’m specifically showing a Python 3 only feature that allows you to put named arguments after *args , so they can only be used by name, not position. What you’re showing allows kw1 to be filled in by position or name — for your version func(1, 2, 3) will fill in a , b , and kw1 , where in my version func(1, 2, 3) will fill in a , b , and args , and require you to do func(1, 2, kw1=3) if you want to fill in kw1 .
If you want to do a mixture of both remember that *args and **kwargs must be the last parameters specified.
def func(arg1,arg2,*args,kw1=None,kw2=None,**kwargs): #Invalid def func(arg1,arg2,kw1=None,kw2=None,*args,**kwargs): #Valid
The comments seem to be based on mixing up how a function definition is constructed compared to how the arguments provided are assigned back to the parameters specified in the definition.
This is the definition of this function which has 6 parameters. It is called by passing named and unnamed arguments to it in a function call.
For this example. When an argument is named when calling the function it can be provided out of order. arg1 and arg2 are mandatory parameters and if not passed to the function as named arguments, then they must be assigned in order from the provided unnamed arguments. kw1 and kw2 have default values provided in the function definition so they are not mandatory, but if not provided for as named arguments they will take any available values from the remaining provided unnamed arguments. Any unnamed arguments left over are provided to the function in an array called args Any named arguments that do not have a corresponding parameter name in the function definition are provided to the function call in a dictionary called kwargs.
Что такое args и kwargs в Python
Python позволяет нам определять три типа аргументов для функции:
- Формальные аргументы, например def add (a, b).
- Переменное количество аргументов без ключевых слов с использованием * args, например def add (* args).
- Переменное количество аргументов с ключевыми словами или именованных аргументов с использованием ** kwargs, например def add (** kwargs).
Некоторые важные моменты об аргументах функций:
- Когда мы определяем аргументы функции, порядок должен быть формальными аргументами, за которыми следуют * args и ** kwargs.
- Не обязательно использовать имена args и kwargs, мы можем использовать и другие имена. Однако их использование принято по соглашению. Это упростит чтение и понимание вашего кода.
- Переменная args имеет тип tuple. Мы можем передать кортеж в качестве аргумента функции для map с args.
- Переменная kwargs имеет тип dict. Таким образом, мы можем передать словарь в качестве аргумента для сопоставления с kwargs.
Зачем нам нужны * args и ** kwargs?
Допустим, у нас есть функция для сложения двух чисел:
def add_two_numbers(a, b): return a + b
Теперь мы хотим расширить это, чтобы добавить три числа. Мы не можем просто изменить эту функцию, потому что она может использоваться в других местах, и это будет серьезное изменение. Итак, мы вводим еще одну функцию для сложения трех чисел.
def add_three_numbers(a, b, c): return a + b + c
Вы видите, к чему я клоню, верно? Поскольку у нас есть возможность указать переменное количество аргументов для функции, мы можем определить универсальную функцию для сложения чисел.
Пример с * args
Давайте определим универсальную функцию для сложения чисел с использованием переменных * args.
def add(*args): total = 0 for arg in args: total = total + arg return total print(add(1, 2)) print(add(1, 2, 3)) print(add(1, 2, 3, 4))
Что это за тип * args и ** kwargs?
def zap(*args, **kwargs): print(type(args)) print(type(kwargs)) zap()
Пример с ** kwargs
Давайте определим функцию, чтобы показать использование переменных ** kwargs.
def kwargs_processor(**kwargs): for k, v in kwargs.items(): print(f'Key= and Value=') kwargs_processor(name='Pankaj', age=34) kwargs_processor(country='India', capital='New Delhi')
Key=name and Value=Pankaj Key=age and Value=34 Key=country and Value=India Key=capital and Value=New Delhi
Передача кортежа и словаря для сопоставления
Давайте посмотрим, как передать значения кортежа для сопоставления с элементами args и словаря переменной kwargs.
t = (10, 30, 60) print(add(*t)) d = kwargs_processor(**d)
100 Key=name and Value=Pankaj Key=age and Value=34
Обратите внимание на использование * при использовании кортежа для сопоставления его значений с аргументами. Аналогичным образом ** используется для сопоставления элементов dict с переменной kwargs.
Когда использовать?
Вы можете использовать их в любой функции, где вы ожидаете переменное количество аргументов. Однако они очень полезны в двух конкретных случаях — имитация ответа функции и написание общей функции-декоратора.
Имитация ответа функции
Допустим, у нас есть класс API, определенный следующим образом:
class APIHelper: def call_api(self, url, input_json): # some complex logic return 'complex_response_data'
Мы можем создать функцию симулятора тестирования и сопоставить ее с функцией API, чтобы сгенерировать тестовый ответ.
class MyTestClass: def test_call_api(self, *args, **kwargs): return "test_response_data" # Assign API function to use our test function APIHelper.call_api = MyTestClass.test_call_api
Давайте теперь посмотрим, что произойдет, когда мы будем использовать наши функции API.
ah = APIHelper() print(ah.call_api()) print(ah.call_api(1, url='https://www.journaldev.com', input_json=<>)) print(ah.call_api(1, 2, url='https://www.journaldev.com'))
test_response_data test_response_data test_response_data
Функция декоратора
Давайте посмотрим, как мы можем определить функцию-декоратор для регистрации переменных функции.
def log_arguments(func): def inner(*args, **kwargs): print(f'Arguments for args:, kwargs:') return func(*args, **kwargs) return inner
Теперь мы можем использовать эту функцию декоратора с любой другой функцией для записи их аргументов в консоль.
@log_arguments def foo(x, y, z): return x + y + z sum_ints = foo(1, 2, z=5) print(sum_ints) @log_arguments def bar(x, *args, **kwargs): total = x for arg in args: total = total + arg for key, value in kwargs.items(): total = total + value return total sum_ints = bar(1, 2, 3, a=4, b=5) print(sum_ints)
Arguments for args:(1, 2), kwargs: 8 Arguments for args:(1, 2, 3), kwargs: 15