Suppose I have a function get_data which takes some number of keyword arguments. Is there some way I can do this
def get_data(arg1, **kwargs):
print arg1, arg2, arg3, arg4
arg1 = 1
data['arg2'] = 2
data['arg3'] = 3
data['arg4'] = 4
get_data(arg1, **data)
So the idea is to avoid typing the argument names in both function calling and function definition. I call the function with a dictionary as argument and the keys of the dictionary become local variables of function and their values are the dictionary values
I tried the above and got error saying global name 'arg2' is not defined. I understand I can change the locals() in the definition of get_data to get the desired behavior.
So my code would look like this
def get_data(arg1, kwargs):
locals().update(kwargs)
print arg1, arg2, arg3, arg4
arg1 = 1
data['arg2'] = 2
data['arg3'] = 3
data['arg4'] = 4
get_data(arg1, data)
and it wouldn't work too. Also cant I achieve the behavior without using locals()?
**kwargs is a plain dictionary. Try this:
def get_data(arg1, **kwargs):
print arg1, kwargs['arg2'], kwargs['arg3'], kwargs['arg4']
Also, check documentation on keyword arguments.
If we examine your example:
def get_data(arg1, **kwargs):
print arg1, arg2, arg3, arg4
In your get_data functions's namespace, there is a variable named arg1, but there is no variable named arg2. so you can not reach a function or a variable that is not in your namespace.
In fact, in your namespace; there is a variable arg1 and a dictionary object called kwargs. using ** notation before the kwargs (name kwargs is not important in here, it can be something else too.) tells your python compiler that kwargs is a dictionary and all values in that dictionary will be evaluated as named parameters in your function definition.
Lets take a look at this example:
def myFunc(**kwargs):
do something
myFunc(key1='mykey', key2=2)
when you call myFunc with named parameters key1 and key2, your function definition acts like
def myFunc(key1=None, key2=None):
but with an exception! since myFunc have no named parameters, compiler do not know how to handle them directly since you can pass any named parameter to your function.
So your function accept those named parameters within a dictionary like you call your function:
myFunc({key1:'mykey', key2:2})
so, your function definition get those parameters within a dictionary. **kwargs defines your dictionary in that point, which also tell compiler that any named parameters will be accepted (by the help of ** signs before the kwargs)
def myFunc(**kwargs):
print kwargs
will print
{key1:'mykey', key2:2}
So in your example, you can use kwargs like a dictionary;
def myFunc(**kwargs):
kwargs['arg2']
kwargs.get('arg3')
I hope it is not complicated (:
Related
Suppose we want to create a callback function which adds two numbers arg1 and arg2. This could be done by returning a function reference like so:
def add(arg1, arg2):
return arg1 + arg2
def partial(f, arg1, arg2):
def wrapper():
return f(arg1, arg2)
return wrapper
callback = partial(add, 2, 4)
print(callback())
Output: 6
How does wrapper remember arg1 and arg2? What do we really return with return wrapper? It seems like not only is part of the function code returned but also its surroundings (in this case variables defined before wrapper). Otherwise there would be a NameError.
Answering your main question, this happens because of something called Closure in python.
When you nest a function inside an enclosing function and return the nested function, the variables passed to the enclosing function are still in the scope of the nested function.
You would often see use of closures for creating decorators in python.
I'm trying to write a decorator that takes a few arguments, and can decorate arbitrary functions. After reading a few code examples, and stepping through the debugger I've figured out how to write it. But I don't fully understand why it works.
def bar(arg1):
def inner_bar(f):
def inner_inner_bar(*args, **kwargs):
new_args = (x + arg1 for x in args)
return f(*new_args, **kwargs)
return inner_inner_bar
return inner_bar
#bar(4)
def foo(x, y):
print("Sum is {0}".format(x+y))
if __name__ == "__main__":
foo(1, 2)
Sum is 11
What I don't fully grasp is how/why the function f exists in the scope of inner_bar but not bar. And similarly that args and kwargs exist in the scope of inner_inner_bar but not inner_bar.
What is Python doing when I use #bar that makes the different variables available in the different methods of my decorator?
What is Python doing when I use #bar that makes the different variables available in the different methods of my decorator?
Note that you're not just using #bar, you're using #bar(4). It works like this:
bar(4) returns a function (inner_bar)
Using #bar(4) to decorate foo calls inner_bar(foo).
inner_bar(foo) returns a function (inner_inner_bar)
This function (inner_inner_bar) is assigned back to the name foo
When you call foo, you are calling inner_inner_bar, so whatever arguments you pass are passed as the *args and **kwargs
What Python is "doing" is calling the functions involved. All of the variables you're asking about (f, args and kwargs) are just function arguments, which, as usual, become available when their function is called. f becomes available when inner_bar is called, namely when you apply the decorator. *args and **kwargs become available when inner_inner_bar is called, namely when you call the decorated function. The only thing that is available when you write bar(4) is arg1, because the other functions haven't been called yet.
I followed this to pass functions as arguments:
Passing functions with arguments to another function in Python?
However, I could not figure out how to pass function with its own arguments as names parameters
def retry(func, *args):
func(*args)
def action(args):
do something
retry(action, arg1, namedArg=arg2)
Here I get an exception:
TypeError: retry() got an unexpected keyword argument 'namedArg'
Normally, I can do:
action(arg1, namedArg=arg2)
Please help/
*args and it's sibling **kwargs are the names generally used for extra arguments and key word arguments. You are passing a kew word argument when you pass namedArg=arg2.
So, try this instead:
def retry(func, *args, **kwargs):
func(*args, **kwargs)
def action(*args, **kwargs):
do something
retry(action, arg1, namedArg=arg2)
If you instead use
def action(args, kwargs):
do something
Then you will end up with args as a list of arguments and kwargs as a dictionary of key word arguments, so in your case
args = [arg1]
kwargs = {'namedArg':arg2}
Read this, keyword arguments in python doc.
As the error clearly states that got an unexpected keyword argument 'namedArg'. where as you are providing only arguments in *args.
You will find plenty of examples to understand keyword arguments.
What you need is functools.
http://docs.python.org/2/library/functools.html#functools.partial
from functools import partial
def action(arg):
do something
def action2(arg=1):
do something
def action3(arg1, arg2=2):
do something
partial(action, arg1)
partial(action, arg1, arg2=3)
I am able to understand what constructors are. But why can't python take initializer lists like c++?
class test:
def __init__(self, arg1, arg2, arg3):
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
how will those arguments ever be set without being so manual?
Thanks.
test1 = test(1, 2, 3)
A constructor is just like any old function, and you pass arguments to it.
Constructor is called once the object is created, not once it is called:
t = test (arg1, arg2, arg3)
Simple - when you instantiate the class later on:
a = test(arg1, arg2, arg3)
a is now a test class, with the 3 arguments set when you initialised it.
The intention behind this is to directly initialize some variables passed to the constructor. The constructor is, as written several times before, called:
t = test(arg1, arg2, arg3)
You have then for the passed parameters defined values in your class.
So I am trying out the new python code for the google app engine search library and I came across a weird syntax. This was:
cls_createDocument(**params)
where params was a dictionary.
The function this refers to is:
#classmethod
def _createDocument(
cls, pid=None, category=None, name=None, description=None,
category_name=None, price=None, **params)
My questions is, what does the **params signify and what does that do to the object?
Thanks!
Jon
Consider a function with default arguments:
def func(foo=3):
print(foo)
The structure of the arguments is (in principle) very similar to a dictionary. The function foo has (essentially) a dictionary of default arguments (in this case {'foo':3}). Now, lets say that you don't want to use the keyword in the function call, but you want to use a dictionary instead -- then you can call foo as:
d = {"foo":8}
func(**d)
This allows you to dynamically change what arguments you are passing to the function func.
This become a little more interesting if you try the following:
d = {"foo":8, "bar":12}
func(**d)
This doesn't work (it is equivalent to foo(foo=8, bar=12), but since bar isn't a valid argument, it fails).
You can get around that problem by giving those extra arguments a place to go inside the definition of foo.
def func( foo=3, **kwargs ):
print(foo,kwargs)
Now, try:
d = {"foo":8, "bar":12}
func(**d) #prints (8, {'bar':12})
All the extra keyword arguments go into the kwargs dictionary inside the function.
This can also be called as:
func(foo=8, bar=12)
with the same result.
This is often useful if funcA calls funcB and you want funcA to accept all of the keywords of funcB (plus a few extra) which is a very common thing when dealing with classes and inheritance:
def funcA(newkey=None,**kwargs):
funcB(**kwargs)
Finally, here is a link to the documentation
The **params parameter represents all the keyword arguments passed to the function as a dictionary.