Python: Passing parameters by name along with kwargs - python

In python we can do this:
def myFun1(one = '1', two = '2'):
...
Then we can call the function and pass the arguments by their name:
myFun1(two = 'two', one = 'one')
Also, we can do this:
def myFun2(**kwargs):
print kwargs.get('one', 'nothing here')
myFun2(one='one')
So I was wondering if it is possible to combine both methods like:
def myFun3(name, lname, **other_info):
...
myFun3(lname='Someone', name='myName', city='cityName', otherInfo='blah')
In general what combinations can we do?
Thanks and sorry for my silly question.

The general idea is:
def func(arg1, arg2, ..., kwarg1=default, kwarg2=default, ..., *args, **kwargs):
...
You can use as many of those as you want. The * and ** will 'soak up' any remaining values not otherwise accounted for.
Positional arguments (provided without defaults) can't be given by keyword, and non-default arguments can't follow default arguments.
Note Python 3 also adds the ability to specify keyword-only arguments by having them after *:
def func(arg1, arg2, *args, kwonlyarg=default):
...
You can also use * alone (def func(a1, a2, *, kw=d):) which means that no arguments are captured, but anything after is keyword-only.
So, if you are in 3.x, you could produce the behaviour you want with:
def myFun3(*, name, lname, **other_info):
...
Which would allow calling with name and lname as keyword-only.
Note this is an unusual interface, which may be annoying to the user - I would only use it in very specific use cases.
In 2.x, you would need to manually make this by parsing **kwargs.

You can add your named arguments along with kwargs. If the keys are available in the calling function It will taken to your named argument otherwise it will be taken by the kwargs dictionary.
def add(a=1, b=2,**c):
res = a+b
for items in c:
res = res + c[items]
print(res)
add(2,3)
5
add(b=4, a =3)
7
add(a =1,b=2,c=3,d=4)
10

It's possible at least for Python 2.7. Keyword arguments get assigned to positional parameters by name, so you can do
In [34]: def func(name, lname, **kwargs):
print 'name='+name, 'lname='+lname
print kwargs
....:
In [35]: func(lname='lname_val', name='name_val', city='cityName', otherInfo='blah')
name=name_val lname=lname_val
{'city': 'cityName', 'otherInfo': 'blah'}
Official docs state it that way:
"If keyword arguments are present, they are first converted to positional arguments, as follows. First, a list of unfilled slots is created for the formal parameters. If there are N positional arguments, they are placed in the first N slots. Next, for each keyword argument, the identifier is used to determine the corresponding slot (if the identifier is the same as the first formal parameter name, the first slot is used, and so on). If the slot is already filled, a TypeError exception is raised. Otherwise, the value of the argument is placed in the slot, filling it (even if the expression is None, it fills the slot)."
https://docs.python.org/2/reference/expressions.html#calls

Related

How to check if the parameters passed to function are correct

I have a list of args and a dict of kwargs
from myapp.tasks import my_function
def run_the_function():
args = ['First', 'Last']
kwargs = {'age': 30}
correct_params = check_if_function_will_run() # how to do this?
# if correct_params are present: run the function in async
my_function.delay(*args, **kwargs)
# else raise error
def my_function(first_name, last_name, email, age=None):
# This is my function to be called in async manner
# It will not run if above args and kwargs are passed to it.
I want to check whether the function will accept these parameters and will run. I thought of using following function:
from inspect import signature
def check_if_function_will_run(function, args, kwargs):
actual_params_len = len(signature(function).parameters) # length of parameters accepted by function
passed_params_len = len(args) + len(kwargs) # length of passed parameters
return actual_params_len == passed_params_len # return if the length of passed and actual parameters is equal
But this approach lacks several cases like:
What is my_function has **kwargs in function definition?
if (actual_args != passed_args and actual_kwargs != passed_kwargs) but (actual_args + actual_kwargs) = (passed_args + passed_kwargs)
These are some of the cases, there might be some cases missing on my side.
So, in the end is there a way to check if the function will accpet the passed args and kwargs, without actually running the function?
Very interesting matter, I gotta say.
Couple of issues when trying this: first of all, every parameter can be passed as a kwarg, as long as it is not passed as an arg (meaning my_func(1,age=7,email=12,last_name=2) is perfectly valid, but my_func(1,age=7,email=12,first_name=2) is not because now the first arg and last kwarg should both be assigned to first_name).
In order to properly do this, I think you'd have to split the parameter list in 2 parts; the part covered by args (so the first len(args) parameters) and the part covered by kwargs. If they overlap (i.e. a key of kwargs is in a position <= len(args)), this param has 2 values -> fail. If a required argument has no assigned value (so len(kwargs) < len(required_kwargs)), fail as well. Don't forget to manually mark any parameter starting with * as not required (as these are the *args and **kwargs parameters).
This is, however, a rather complex calculation, and your time would probably be better spent using try/except; also efficiencywise, as the function won't run if it lacks arguments.

Can I pass a function and a varying number of arguments to another function?

can someone say what the best method to do this would be?
I want to have a function, overall_function that I pass other functions to. But the other functions don't always have the same or type of arguments.
So what would be the correct syntax to do:
def overall_function(function, arguments):
function(arguments)
do other stuff
I'd like arguments to be:
arg1 = 'foo', arg2 = 53, ...
Thank you!
Take variable number of arguments:
def overall_function(function, *positional, **keyword):
function(*positional, **keyword)
Now, you can pass the arguments like:
overall_function(function, 1, 2, foo='bar')
and this will execute the function as:
function(1, 2, foo='bar')
positional would be a tuple: (1, 2) (these two are positional arguments).
keyword would be a dict: {'foo': 'bar'} (this is a keyword argument).
Looking for *args and **kwargs
def overall_function(function, *args, **kwargs):
function(*args, **kwargs)
do other stuff
You might be better off passing in a lambda as opposed to two arguments so you can delay the execution of the function till you need it, and still keeping the parameters contained together
def overall_function(lambda_func):
lambda_func()
overall_function(lambda: function(used,as,normal))

In Python, how to add a keyword argument to a function with *args and **kwargs? [duplicate]

In python we can do this:
def myFun1(one = '1', two = '2'):
...
Then we can call the function and pass the arguments by their name:
myFun1(two = 'two', one = 'one')
Also, we can do this:
def myFun2(**kwargs):
print kwargs.get('one', 'nothing here')
myFun2(one='one')
So I was wondering if it is possible to combine both methods like:
def myFun3(name, lname, **other_info):
...
myFun3(lname='Someone', name='myName', city='cityName', otherInfo='blah')
In general what combinations can we do?
Thanks and sorry for my silly question.
The general idea is:
def func(arg1, arg2, ..., kwarg1=default, kwarg2=default, ..., *args, **kwargs):
...
You can use as many of those as you want. The * and ** will 'soak up' any remaining values not otherwise accounted for.
Positional arguments (provided without defaults) can't be given by keyword, and non-default arguments can't follow default arguments.
Note Python 3 also adds the ability to specify keyword-only arguments by having them after *:
def func(arg1, arg2, *args, kwonlyarg=default):
...
You can also use * alone (def func(a1, a2, *, kw=d):) which means that no arguments are captured, but anything after is keyword-only.
So, if you are in 3.x, you could produce the behaviour you want with:
def myFun3(*, name, lname, **other_info):
...
Which would allow calling with name and lname as keyword-only.
Note this is an unusual interface, which may be annoying to the user - I would only use it in very specific use cases.
In 2.x, you would need to manually make this by parsing **kwargs.
You can add your named arguments along with kwargs. If the keys are available in the calling function It will taken to your named argument otherwise it will be taken by the kwargs dictionary.
def add(a=1, b=2,**c):
res = a+b
for items in c:
res = res + c[items]
print(res)
add(2,3)
5
add(b=4, a =3)
7
add(a =1,b=2,c=3,d=4)
10
It's possible at least for Python 2.7. Keyword arguments get assigned to positional parameters by name, so you can do
In [34]: def func(name, lname, **kwargs):
print 'name='+name, 'lname='+lname
print kwargs
....:
In [35]: func(lname='lname_val', name='name_val', city='cityName', otherInfo='blah')
name=name_val lname=lname_val
{'city': 'cityName', 'otherInfo': 'blah'}
Official docs state it that way:
"If keyword arguments are present, they are first converted to positional arguments, as follows. First, a list of unfilled slots is created for the formal parameters. If there are N positional arguments, they are placed in the first N slots. Next, for each keyword argument, the identifier is used to determine the corresponding slot (if the identifier is the same as the first formal parameter name, the first slot is used, and so on). If the slot is already filled, a TypeError exception is raised. Otherwise, the value of the argument is placed in the slot, filling it (even if the expression is None, it fills the slot)."
https://docs.python.org/2/reference/expressions.html#calls

What does replace = options.pop('replace', True) accomplish in this code? [duplicate]

class a(object):
data={'a':'aaa','b':'bbb','c':'ccc'}
def pop(self, key, *args):
return self.data.pop(key, *args)#what is this mean.
b=a()
print b.pop('a',{'b':'bbb'})
print b.data
self.data.pop(key, *args) ←------ why is there a second argument?
The pop method of dicts (like self.data, i.e. {'a':'aaa','b':'bbb','c':'ccc'}, here) takes two arguments -- see the docs
The second argument, default, is what pop returns if the first argument, key, is absent.
(If you call pop with just one argument, key, it raises an exception if that key's absent).
In your example, print b.pop('a',{'b':'bbb'}), this is irrelevant because 'a' is a key in b.data. But if you repeat that line...:
b=a()
print b.pop('a',{'b':'bbb'})
print b.pop('a',{'b':'bbb'})
print b.data
you'll see it makes a difference: the first pop removes the 'a' key, so in the second pop the default argument is actually returned (since 'a' is now absent from b.data).
So many questions here. I see at least two, maybe three:
What does pop(a,b) do?/Why are there a second argument?
What is *args being used for?
The first question is trivially answered in the Python Standard Library reference:
pop(key[, default])
If key is in the dictionary, remove it and return its value, else return default.
If default is not given and key is not in the dictionary, a KeyError is raised.
The second question is covered in the Python Language Reference:
If the form “*identifier” is present,
it is initialized to a tuple receiving
any excess positional parameters,
defaulting to the empty tuple. If the
form “**identifier” is present, it is
initialized to a new dictionary
receiving any excess keyword
arguments, defaulting to a new empty
dictionary.
In other words, the pop function takes at least two arguments. The first two get assigned the names self and key; and the rest are stuffed into a tuple called args.
What's happening on the next line when *args is passed along in the call to self.data.pop is the inverse of this - the tuple *args is expanded to of positional parameters which get passed along. This is explained in the Python Language Reference:
If the syntax *expression appears in
the function call, expression must
evaluate to a sequence. Elements from
this sequence are treated as if they
were additional positional arguments
In short, a.pop() wants to be flexible and accept any number of positional parameters, so that it can pass this unknown number of positional parameters on to self.data.pop().
This gives you flexibility; data happens to be a dict right now, and so self.data.pop() takes either one or two parameters; but if you changed data to be a type which took 19 parameters for a call to self.data.pop() you wouldn't have to change class a at all. You'd still have to change any code that called a.pop() to pass the required 19 parameters though.
def func(*args):
pass
When you define a function this way, *args will be array of arguments passed to the function. This allows your function to work without knowing ahead of time how many arguments are going to be passed to it.
You do this with keyword arguments too, using **kwargs:
def func2(**kwargs):
pass
See: Arbitrary argument lists
In your case, you've defined a class which is acting like a dictionary. The dict.pop method is defined as pop(key[, default]).
Your method doesn't use the default parameter. But, by defining your method with *args and passing *args to dict.pop(), you are allowing the caller to use the default parameter.
In other words, you should be able to use your class's pop method like dict.pop:
my_a = a()
value1 = my_a.pop('key1') # throw an exception if key1 isn't in the dict
value2 = my_a.pop('key2', None) # return None if key2 isn't in the dict
>>> def func(a, *args, **kwargs):
... print 'a %s, args %s, kwargs %s' % (a, args, kwargs)
...
>>> func('one', 'two', 'three', four='four', five='five')
a one, args ('two', 'three'), kwargs {'four': 'four', 'five': 'five'}
>>> def anotherfunct(beta, *args):
... print 'beta %s, args %s' % (beta, args)
...
>>> def func(a, *args, **kwargs):
... anotherfunct(a, *args)
...
>>> func('one', 'two', 'three', four='four', five='five')
beta one, args ('two', 'three')
>>>

When to use * and ** as a function argument in python function

When can I pass * and ** in the argument of a Python function? i.e.:
def fun_name(arg1, *arg2 , ** arg3):
As you've stated your question, you aren't using them in the arguments (which occur when you are calling a function), you are using them in the parameters which occur when you are creating a function. The * and ** operators serve different purposes in each of those situations.
When you are defining a function, they specify that positional arguments will be placed in a tuple and that keyword arguments will be placed in a dict. Yes I did just say arguments, but they are applied to paramaters in this case.
def example(*args, **kwargs):
print "args: {0}".format(args)
print "kwargs: {0}".format(kwargs)
example(1, 2, 'a', foo='bar', bar='foo')
when run, this outputs:
args: (1, 2, 'a')
kwargs: {'foo': 'bar', 'bar': 'foo'}
Do you see what I mean when I say that we applied it to the paramaters in the function definition? the arguments are 1, 2, 'a', foo='bar', bar='foo'. the paramaters are *args, **kwargs.
Now here's an example applying them to arguments.
def example2(a, b, foo=None, bar=None):
print "a: {0}, b:{1}, foo:{2}, bar: {3}".format(a, b, foo, bar)
args = (1, 2)
kwargs = {'foo': 'bar', 'bar': 'foo'}
example2(*args, **kwargs)
This outputs:
a: 1, b:2, foo:bar, bar: foo
You can see that when we apply them to arguments (that is when we are calling the function), * has the effect of expanding a list or tuple to fill the positional arguments of a function and ** has the effect of expanding a dictionary to fill the keyword arguments of a function. You just need to make sure that there are enough and not too much arguments in total after the expansions have taken place.
in the last example, the arguments are *args, **kwargs and the parameters are a, b, foo=None, bar=None
When can I pass * and ** in the argument of a Python function? i.e.:
Short answer: when you require variable number of argument to be passed to your function.
That said, I honestly think that this a very broad question. You will be much better off reading more about these concepts, trying them off and then asking an specific questions here.
#Wooble's answer will help you; but what will help you even more is to understand what *args and **kwargs do. Then you can use them as befits the situations you encounter.
You can learn more about the variable and keyword arguments concepts for example at:
http://www.network-theory.co.uk/docs/pytut/KeywordArguments.html
http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
Any time you want your function to accept non-named positional arguments (*), or additional named arguments (**).
It's certainly possible to include *args, **kwargs in every function definition, although this might not be a great idea if passing more arguments won't actually have any effect.

Categories

Resources