Difference call function with asterisk parameter and without - python

I know what the meaning of an asterisk is in a function definition in Python.
I often, though, see asterisks for calls to functions with parameters like:
def foo(*args, **kwargs):
first_func(args, kwargs)
second_func(*args, **kwargs)
What is the difference between the first and the second function call?

Let args = [1,2,3]:
func(*args) == func(1,2,3) - variables are unpacked out of list (or any other sequence type) as parameters
func(args) == func([1,2,3]) - the list is passed
Let kwargs = dict(a=1,b=2,c=3):
func(kwargs) == func({'a':1, 'b':2, 'c':3}) - the dict is passed
func(*kwargs) == func(('a','b','c')) - tuple of the dict's keys (in random order)
func(**kwargs) == func(a=1,b=2,c=3) - (key, value) are unpacked out of the dict (or any other mapping type) as named parameters

The difference is how the arguments are passed into the called functions. When you use the *, the arguments are unpacked (if they're a list or tuple)—otherwise, they're simply passed in as is.
Here's an example of the difference:
>>> def add(a, b):
... print a + b
...
>>> add(*[2,3])
5
>>> add([2,3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly 2 arguments (1 given)
>>> add(4, 5)
9
When I prefixed the argument with *, it actually unpacked the list into two separate arguments, which were passed into add as a and b. Without it, it simply passed in the list as a single argument.
The same is the case for dictionaries and **, except they're passed in as named arguments rather than ordered arguments.
>>> def show_two_stars(first, second='second', third='third'):
... print "first: " + str(first)
... print "second: " + str(second)
... print "third: " + str(third)
>>> show_two_stars('a', 'b', 'c')
first: a
second: b
third: c
>>> show_two_stars(**{'second': 'hey', 'first': 'you'})
first: you
second: hey
third: third
>>> show_two_stars({'second': 'hey', 'first': 'you'})
first: {'second': 'hey', 'first': 'you'}
second: second
third: third

def fun1(*args):
""" This function accepts a non keyworded variable length argument as a parameter.
"""
print args
print len(args)
>>> a = []
>>> fun1(a)
([],)
1
# This clearly shows that, the empty list itself is passed as a first argument. Since *args now contains one empty list as its first argument, so the length is 1
>>> fun1(*a)
()
0
# Here the empty list is unwrapped (elements are brought out as separate variable length arguments) and passed to the function. Since there is no element inside, the length of *args is 0
>>>

Related

Why does this print `3 {}` and not `2 {'a': 3}`?

def f(a=2, **b):
print(a,b)
f(**{'a':3})
Why does this print 3 {} and not 2 {'a': 3}?
I can understand why it printed 3 {} if it was f(a=3) but I don't understand the output in this case.
The unpacking operator, when used on a dict, passes the dict's contents as keyword arguments.
In other words, the following two lines are functionally identical:
f(a=3)
f(**{'a':3})
Since a is getting passed explicitly as a keyword argument, the default value of 2 is overwritten. And since no other arguments are passed, the **b argument is left empty.
The call f(**{'a':3}) is same as f(a=3), so the value of a is 3 and not the default 2. For b , using the unpacking operator **, it means to save all the other mapping variable into it, as there is no one, it values an empty dict
a is 3
b is empty dict, {}
So it prints 3 {}
To use b you need to pass argument named differently as a
# both print: 3 {'foo': 'bar', 'number': 100}
f(**{'a':3, 'foo':'bar', 'number':100})
f(a=3, foo='bar', number=100)

How to pass large number of keyword arguments automatically in python

I am calling a function
foo(x,y0=y[0],y1=y[1],y2=y[2],...,y<d>=y[<d>])
where <d> is a large number that may vary from call to call. All arguments except x are keyword arguments.
I didn't write foo myself, so I cannot just pass y as a list instead. Is there an automated way to split a list into keyword arguments?
First, build a list of name, value pairs, then convert that to a dictionary and pass it to the function.
y_vals = [ 1, 2, 3, 'a', 'b', 'c' ]
arg_dict = dict(('y%d' % i, v) for i, v in enumerate(y_vals))
foo(x, **arg_dict)
Use * for passing unpacked arguments from a list, You can send in normal arguments in place of keyword arguments, just make sure you pass them in proper order, for e.g:
def foo(x, y1=None, y2=None, y3=None, y4=None, ... , yN=None):
# func stuff
You can pass a list to the function unpacked, like:
arguments = ["arg-y1", "arg-y2", "arg-y3", ... , "arg-yN"]
foo (x, *arguments)
As they are keyword arguments, they will have some default value.
If you want to pass only a few specific values, you can use the Dictionary and ** for kw:
kwargs = {"y1": "arg-y1", "y3": "arg-Y3" }
foo (x, **kwargs)
You can use **kwargs to let your functions take an arbitrary number of keyword arguments ("kwargs" means "keyword arguments"):
>>> def print_keyword_args(**kwargs):
... # kwargs is a dict of the keyword args passed to the function
... for key, value in kwargs.iteritems():
... print "%s = %s" % (key, value)
...
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe
You can also use the **kwargs syntax when calling functions by constructing a dictionary of keyword arguments and passing it to your function:
>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith
The Python Tutorial contains a good explanation of how it works, along with some nice examples.
For your case to convert list to keyword arguments :
# y is a list with arguments stored.
kwargs = {}
for arg in range(len(y)):
kwargs['y'+str(arg)] = y[arg]
foo(**kwargs)

Combine single and multi argument variables in a function call for Python

I wrote the following function to return a subset of a dictionary but want to insist on having at least one key provided in the input arguments.
def getProperty(self,x, *key):
key = [k for k in key]
key.insert(0,x)
return {k:self.__properties[k] for k in key if k in self.__properties}
The code works.
I know the insert is not really necessary since dictionary elements aren't ordered. What I really wish I could do is to get rid of the first for-loop that creates a list by extracting elements from the multi-argument tuple.
Something like
key = [x] + [key]
but it does not work.
This should do what you need:
def getProperty(self,x, *key):
key = (x,)+key
return {k:self.__properties[k] for k in key if k in self.__properties}
If you want to insist on there being at least one argument then you should assert that the args tuple is not empty
>>> def get_property(*args):
... assert (args != ()), "There must be at least one argument"
... print(args)
...
>>> get_property('a')
('a',)
>>> get_property('a', 'b')
('a', 'b')
>>> get_property()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in get_property
AssertionError: There must be at least one argument
>>>
There's no need, then, to do anything fancy to provide one separate argument when you call the method and you can catch the AssertionError in the calling statement if required.

what is the asterisk in "replace(*something)" for? (python) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does *args and **kwargs mean?
I' just reading Mining the social web and encountered a python syntax that I can't figure out:
transforms = [(', Inc.', ''), (', Inc', ''), (', LLC', ''), (', LLP', '')]
"google, Inc.".replace(*transforms[0])
But if I type
*transforms[0]
in the interpreter, it says it is invalid syntax. I googled it, but the python docu really is not up for the job.
So what does the asterisk means here please? Thank you all.
The *argument format in python means: use all elements in the sequence argument and pass them as arguments to the function.
In this specific case, that translates to:
"google, Inc.".replace(', Inc.', '')
This is easiest demonstrated:
>>> def foo(arg1, arg2):
... print arg1, arg2
...
>>> arguments = ('spam', 'eggs')
>>> foo(*arguments)
spam, eggs
You can also use the **kw double star format to pass in keyword arguments:
>>> def foo(arg1='ham', arg2='spam'):
... print arg1, arg2
...
>>> arguments = dict(arg2='foo', arg1='bar')
>>> foo(**arguments)
bar, foo
and you can use the same spelling in a function definition to capture arbitrary positional and keyword arguments:
>>> def foo(*args, **kw):
... print args, kw
...
>>> foo('arg1', 'arg2', foo='bar', spam='eggs')
('arg1', 'arg2'), {'foo': 'bar', 'spam': 'eggs'}
The asterisk unpacks an iterable. I think it is best explained with an example:
>>> def exampleFunction (paramA, paramB, paramC):
print('A:', paramA)
print('B:', paramB)
print('C:', paramC)
>>> myTuple = ('foo', 'bar', 'baz')
>>> myTuple
('foo', 'bar', 'baz')
>>> exampleFunction(myTuple)
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
exampleFunction(myTuple)
TypeError: exampleFunction() takes exactly 3 arguments (1 given)
>>> exampleFunction(myTuple[0], myTuple[1], myTuple[2])
A: foo
B: bar
C: baz
>>> exampleFunction(*myTuple)
A: foo
B: bar
C: baz
As you can see, we defined a function that takes three arguments and a tuple with three elements. Now if we want to use the values from the tuple directly, we cannot just pass the tuple and have it working. We could pass each element separately but that is just very verbose. What we do instead is use the asterisk to unpack the tuple and essentially use the elements from the tuple as arguments.
There is a second usage for the unpacking functionality when working with a unknown number of parameters:
>>> def example2 (*params):
for param in params:
print(param)
>>> example2('foo')
foo
>>> example2('foo', 'bar')
foo
bar
>>> example2(*myTuple)
foo
bar
baz
The asterisk allows us here to define a parameter that takes all the remaining values that were passed and packs it into an iterable, so we can iterate it.
It turns the tuple passed into a list of arguments. So
"google, Inc.".replace(*transforms[0])
becomes
"google, Inc.".replace(', Inc.', '')
This way you can programatically construct the list of arguments that are being passed (with variable length being a key advantage).
Check section 4.7.4 of the Python tutorial: http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions
But if I type
*transforms[0]
in the interpreter, it says it is invalid syntax.
The * in front of transforms[0] only has meaning in a function call.
An alternative way of making this call with the data in the first tuple in the list is:
"Google, Inc.".replace(transforms[0][0],transforms[0][1])

Can I Pass Dictionary Values/Entry and Keys to function

I am writing a function and intended to use a dictionary key and its value as parameters. For example:
testDict={'x':2,'xS':4}
def newFunct(key,testDict['key']):
newvalue=key+str(testDict['key'])
return newValue
for key in testDict:
newValue=newFunct(key,testDict[key])
print newValue
I get a SyntaxError: invalid syntax when I hit the return button after typing the semicolon. I am guessing this is telling me I can't pass a dictionary value in that form. Presumably I can define a new variable
for key in testDict:
xdixt=testDict[key]
newValue=newFunct(key,xdixt)
and def the function using xdixt
but I am hoping there is some trick that I am missing. I Googled and found some reference to unpacking a dictionary but that didn't seem to work.
This Python stuff is really cool. My question was came about because I am trying to use some values I stored in a dictionary to create a new directory. Based on the material I read from Stephan's answer I wondered about how to generalize the information I learned. My directory name has five different pieces to it, each piece is the result of processing the values from myDict. The expression to create the directory name was getting too complicated and in my opinion too complicated to easily read. so I wondered if I could use the same approach to put the pieces into a list and then unpack them when it came time to create the directory name and it worked!
def createDirectory(myKey,**myDict):
pathList=[]
pathList.append(myDict['subKey1'])
pathList.append(myDict['subKey2'].lstrip('0'))
pathList.append(myDict['subKey3'])
etc
myPath=os.path.join(*myList)
os.makedirs(myPath)
return(myPath)
Is this what you want?
def func(**kwargs):
for key, value in kwargs.items():
pass # Do something
func(**myDict) # Call func with the given dict as key/value parameters
(See the documentation for more about keyword arguments. The keys in myDict must be strings.)
Edit: you edited your question to include the following:
I think the ** notation in front of myDict instructs the function to expect a dictionary and to unpack the key (the first *) and the value, the second *
This is not correct. To understand what is happening, you must consider the following:
A function can have multiple formal parameters (a and b in this case):
def f1(a, b): pass
We can pass positional arguments to such function (like in most other languages):
f1(2, 3)
We can also pass keyword arguments:
f1(a=2, b=3)
We can also mix these, but the positional arguments must come first:
f1(2, b=3)
f1(a=2, 3) # SyntaxError: non-keyword arg after keyword arg
There is a way to let a function accept an arbitrary number of positional arguments, which it can access as a tuple (args in this case):
def f2(*args): assert isinstance(args, tuple)
Now we can call f2 using separately specified arguments, or using a list whose contents first need to be unpacked, using a syntax similar to the notation used for *args:
f2(2, 3)
f2(*[2, 3])
Likewise, an arbitrary number of keyword arguments may be accepted:
def f3(**kwargs): pass
Note that f3 does not ask for a single argument of type dict. This is the kind of invocations it expects:
f3(a=2, b=3)
f3(**{'a': 2, 'b': 3})
All arguments to f3 must be named:
f3(2, 3) # TypeError: f3() takes exactly 0 arguments (2 given)
Putting all of this together, and remembering that positional arguments must come first, we may have:
>>> def f4(a, b, *args, **kwargs):
... print('%r, %r' % (args, kwargs))
...
>>> f4(2, 3)
(), {}
>>> f4(2, 3, 4, 5)
(4, 5), {}
>>> f4(2, 3, x=4, y=5)
(), {'y': 5, 'x': 4}
>>> f4(2, 3, 4, 5, x=6, y=7)
(4, 5), {'y': 7, 'x': 6}
>>> f4(2, *[3, 4, 5], **{'x': 6, 'y': 7})
(4, 5), {'y': 7, 'x': 6}
Pay special attention to the following two errors:
>>> f4(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f4() takes at least 2 arguments (1 given)
>>> f4(2, 3, a=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f4() got multiple values for keyword argument 'a'
The second error should help you explain this behavior:
>>> f4(**{'foo': 0, 'a': 2, 'b': 3, 'c': 4})
(), {'c': 4, 'foo': 0}
Not sure why we are bringing in kwargs, this is much simpler than that. You said you're new to Python, I think you just need some Python fundamentals here.
def newFunct(key,testDict['key']):
Should be:
def newFunct(key, val):
There's no reason to use any special syntax on your second parameter to indicate that it's coming from a dictionary. It's just a parameter, you just happen to be passing the value from a dictionary item into it.
Further, once it's in the function, there's no reason to treat it in a special way either. At this point it's just a value. Which means that:
newvalue=key+str(testDict[key])
Can now just be:
newvalue=key+str(val)
So when you call it like this (as you did):
newValue=newFunct(key,testDict[key])
testDict[key] resolves to the value at 'key', which just becomes "val" in the function.
An alternate way, if you see it fit for whatever reason (and this is just something that's good to know), you could define the function thusly:
def newFunct(key, testDict):
Again, the second parameter is just a parameter, so we use the same syntax, but now we're expecting it to be a dict, so we should use it like one:
newvalue=key+str(testDict[key])
(Note: don't put quotes around 'key' in this case. We're referring to the variable called 'key', not a key called 'key'). When you call the function, it looks like this:
newValue=newFunct(key,testDict)
So unlike the first case where you're just passing one variable from the dictionary, you're passing a reference to the whole dictionary into the function this time.
Hope that helps.
why don't you just do:
[k + str(v) for k, v in test_dict.iteritems()]
or for py3k:
[k + str(v) for k, v in test_dict.items()]
edit
def f(k, v):
print(k, v) # or do something much more complicated
for k, v in testDict.items():
f(k, v)
From your description is seems like testDict is some sort of global variable with respect to the function. If this is the case - why do you even need to pass it to the function?
Instead of your code:
testDict={'x':2,'xS':4}
def newFunct(key,testDict[key]):
newvalue=key+str(testDict[key])
return newValue
for key in testDict:
newValue=newFunct(key,testDict[key])
print newValue
You can simply use:
testDict={'x':2,'xS':4}
def newFunct(key):
newvalue=key+str(testDict[key])
return newValue
for key in testDict:
newValue=newFunct(key)
print newValue
If testDict is not meant to be in the global scope (which makes sense...), I would recommend simply passing a name for the dictionary and not "messing around" with variable length argument lists in this case:
testDict={'x':2,'xS':4}
def newFunct(key,dictionary):
newvalue=key+str(dictionary[key])
return newValue
for key in testDict:
newValue=newFunct(key,testDict)
print newValue

Categories

Resources