*args in function with Python - python

I was trying to define a simple sum function in python.
My code is:
def sum_all_num(*args):
return sum(*args)
But I got error. I understand the *args will gather all arguments in a tuple, but why I can not use sum function to sum it?

sum() takes an iterable. Just remove the * and pass the args tuple directly.
Example:
x = 1, 2, 3
print(sum(x))
Results:
6

sum() takes only one argument (an iterable).
So, instead of unpacking args with *, just pass the args variable to it:
def sum_all_num(*args):
return sum(args)
Test:
>>> sum_all_num(1,2,3)
6

Related

Python function that receives an unknown number of arguments

I would like to write a function that receives an unknown number of arguments, multiplies them and prints the result.
I use *args but I get the sames result if I use a tuple as the parameter.
# Using *args
def mult(*args):
ans = 1
for i in args:
ans *= i
print(ans)
# using a tuple
def multT(t):
ans = 1
for i in t:
ans *= i
print(ans)
mult(1,2,3,4)
multT((1,2,3,4))
Both functions print 24.
Is there any reason to prefer using *args and not a tuple? If in this case it makes no difference, are there other cases when I would have to use *args and not a tuple?

When do I need a * character in function definition in Python?

I have the two functions I defined as below,
def sumit(func,*args):
return func(*args)
def sumitt(*args):
return sum(args)
sumit(sumitt,2,3,4)
I experimented a bit by changing the second line to return func(args) and I got an error. But why in the 4th line, it's sum(args) rather than sum(*args)? What caused this inconsistency?
To apply the function on each of its arguments, you need the * to unpack the arguments of the function.
So func(*args) is synomnymous to func(arg1, arg2,...,argn)
Have a look at unpacking in action:
>>> first, second, third = (1, 2, 3)
>>> first
1
>>> second
2
>>> third
3
But with sum, the signature of the function requires that it take an iterable, therefore sum(arg) applies sum (a summation) directly on the tuple of arguments arg.
If you look at the documentation sum is defined as -
`sum(iterable[, start])`
which means it is taking an iterable object, which will traverse the arguments itself.
So
def sumit(func,*args):
return func(*args)
def sumitt(*args):
print (args)
print (*args)
return sum(args)
Out -
(1, 2, 3)
1 2 3
Now as you can see args is a tuple whereas *args unwraps the elements... the tuple is what sum accepts where as your function is accepting a list which it is unpacking. What you could've done is
def sumit(func,*args):
return func(args)
def sumitt(args):
print (args)
print (*args)
return sum(args)
Now you send the whole tuple to the function sumitt which you can unpack with *args..
1 2 3
This is also work in the same way but now you can see what was happening..
*args in a function signature accepts an arbitrary list of of arguments and makes it available in the function's scope in a variable named args
for example
def my_print(*args):
"""print all arguments passed in"""
for arg in args:
try:
print(arg)
except:
print('argument not printable')
d = 'hello'
my_print('a', 1, 'b', d)
# outputs:
a
1
b
hello
putting a * in front of a list or tuple in a function call unpacks the list
my_list = ['a', 1, 'b', d]
my_print(*my_list)
# produces the same output as above.
so, the first function you defined:
def sumit(func,*args):
return func(*args)
accepts a callable as the first positional argument
accepts an arbitrary list of arguments for the 2nd argument on wards
make these arguments available in a list named args
returns the callable with the list args unpacked
In this function the 2nd line cannot be return func(args), unless the function passed accepts a list as the first positional parameter, and has no other required parameter
the function sum accepts a iterable (list or tuple) of numbers and adds them up.
you can call sum like this
my_sum = sum([2, 3, 4])
but the sumitt function takes arguments and converts them to a list before passing it to the sum function
so, you can call sumitt(2, 3, 4) and it will return sum([2, 3, 4])
Now, sumitt is further wrapped in sumit, so the function call
sumit(sumitt,2,3,4)
calls sumitt(2, 3, 4), which in turn calls sum([2, 3, 4])
It is also possible to call the sum function through sumit like this:
sumit(sum, [2, 3, 4])
The 2nd function sumitt changes the signature of the sum function. This is useful in cases where you'll be calling many different functions dynamically and you want their signatures to be the same. The first function lets you call an arbitrary function with arbitrarily passed parameters.
for example, if I defined a mean function like this:
def mean(*args):
return sum(args) / len(args)
Then, mean and sum have dissimilar signatures.
At another place in my code I had to call either the mean function or the sum function, I could write it like this:
def sumitt(*args):
return sum(args)
def apply_func(func, *args):
return func(*args)
apply_func(sumitt, 2, 3, 4)
# returns 9
apply_func(mean, 2, 3, 4)
# returns 3
If your function is expecting individual arguments but you have a sequence (a list, for example), you must specify the character * so that the list gets expanded (unpacked) into the sequence (otherwise it would be treated as one parameter)
On the other hand, because the function sum (a built-in function python) expects the sequence (only one parameter) you must not expand it before calling it.
Imagine your args is:
args = [1, 2, 3, 4]
By using func(*args), when func is evaluated, it would be func(1, 2, 3, 4).
However sum(args) would be evaluated as func([1, 2, 3, 4])

Using "*" inside python

I am supposed to use find out how to use "*" to sum up several values.
For example:
sum_all(1, 2, 3, 4, 5)
15
sum_all(49, 51)
100
Given a general function like :
def sum_all(*args)
I am unsure how to implement the * within the code.
def sum_all(*args):
total = 0
for arg in args:
total += sum(arg)
return total
To be different from the others which i think posted at the same time as me, i'll explain and come up with another solution.
When doing *args you can look at it this way:
def sum_all([arg1, arg2, arg3, ...]):
Which would tedious to code and since you don't know how many parameters are given, you do *args instead, which dynamically takes a "endless" amount of arguments in a list format.
The most neat way i can think of:
def sum_all(*args):
return sum(sum(arg) for arg in args)
This assumes the input is something along the lines of:
sum_all([1,2,3], [5,5], [10,10])
If not just skip one of the sums:
def sum_all(*args):
return sum(args)
You can treat the passed in variable as an iterable.
sum_nums = 0
for val in args:
sum_nums += val
A good read would be the top answer in this question.
def sum_all(*args):
s = 0
for n in args:
s = s + n
return s
In short:
def sum_all(*args):
return sum(args)
*args represent here a sequence of positional arguments, that you can later iterate over. Fortunately, builtin sum() takes single iterable as argument, so you can just pass it there.
More info you can find in docs:
http://docs.python.org/2/faq/programming.html#how-can-i-pass-optional-or-keyword-parameters-from-one-function-to-another
Just 2 lines of code :)
def sum_all(*args):
return (sum(args[0])
You can try as,
def sum_all(*args):
return sum([i for i in args])

How to unpack a tuple while calling an external method in Python?

I call a method of an external library multiple times in my class like this:
class MyClass:
const_a = "a"
const_b = True
const_c = 1
def push(self, pushee):
with ExternalLibrary.open(self.const_a, self.const_b, self.const_c) as el:
el.push(pushee)
def pop(self):
with ExternalLibrary.open(self.const_a, self.const_b, self.const_c) as el:
return el.pop()
The lines containing the with statement are bugging me, because they require passing the the constants as arguments every time. I would like to store the arguments in a predefined data structure like a tuple and pass that to the external library.
You can do this:
args = (const_a, const_b, const_c)
ExternalLibrary.open(*args)
The * syntax unpacks an iterable (tuple, list, etc.) into individual arguments in a function call. There is also a ** syntax for unpacking a dictionary into keyword arguments:
kwargs = {'foo': 1, 'bar': 2}
func(**kwargs) # same as func(foo=1, bar=2)
You can also use both in the same call, like func(*args, **kwargs).

Expanding tuples into arguments

Suppose I have a function like:
def myfun(a, b, c):
return (a * 2, b + c, c + b)
Given a tuple some_tuple = (1, "foo", "bar"), how can I use some_tuple to call myfun, to get the result (2, "foobar", "barfoo")
I know could define myfun so that it accepts the tuple directly, but I want to call the existing myfun.
See also: What do the * (star) and ** (double star) operators mean in a function call?.
myfun(*some_tuple) does exactly what you request. The * operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.
Note that you can also expand part of argument list:
myfun(1, *("foo", "bar"))
Take a look at the Python tutorial section 4.7.3 and 4.7.4.
It talks about passing tuples as arguments.
I would also consider using named parameters (and passing a dictionary) instead of using a tuple and passing a sequence. I find the use of positional arguments to be a bad practice when the positions are not intuitive or there are multiple parameters.
This is the functional programming method. It lifts the tuple expansion feature out of syntax sugar:
apply_tuple = lambda f, t: f(*t)
Redefine apply_tuple via curry to save a lot of partial calls in the long run:
from toolz import curry
apply_tuple = curry(apply_tuple)
Example usage:
from operator import add, eq
from toolz import thread_last
thread_last(
[(1,2), (3,4)],
(map, apply_tuple(add)),
list,
(eq, [3, 7])
)
# Prints 'True'
Similar to #Dominykas's answer, this is a decorator that converts multiargument-accepting functions into tuple-accepting functions:
apply_tuple = lambda f: lambda args: f(*args)
Example 1:
def add(a, b):
return a + b
three = apply_tuple(add)((1, 2))
Example 2:
#apply_tuple
def add(a, b):
return a + b
three = add((1, 2))

Categories

Resources