How can I unpack tuple when other variables are needed? - python

According to this, I can call a function that takes N arguments with a tuple containing those arguments, with f(*my_tuple).
Is there a way to combine unpacking and unpacked variables?
Something like:
def f(x,y,z):...
a = (1,2)
f(*a, 3)

The code you supplied (f(*a, 3)) is valid for python 3. For python 2, you can create a new tuple by adding in the extra values. Then unpack the new tuple.
For example if you had the following function f:
def f(x, y, z):
return x*y - y*z
print(f(1,2,3))
#-4
Attempting your code results in an error in python 2:
a = (1,2)
print(f(*a,3))
#SyntaxError: only named arguments may follow *expression
So just make a new tuple:
new_a = a + (3,)
print(f(*new_a))
#-4
Update
I should also add another option is to pass in a named argument after the * expression (as stated in the SyntaxError):
print(f(*a, z=3))
#-4

A little heavy, but you can use functools.partial to partially apply f to the arguments in a before calling the resulting callable on 3.
from functools import partial
partial(f, *a)(3)
This is more useful if you plan on making a lot of calls to f with the same two arguments from a, but with different 3rd arguments; for example:
a = (1,2)
g = partial(f, *a)
for k in some_list:
g(k) # Same as f(1,2,k)

as #pault said - you can create a new tuple , and you can do another thing which is:
pass the *a as the last variable to a function, for example :
def f(x,y,z):...
a = (1,2)
f(3, *a)
worked for me in Python 2.7

Related

What is the point of using *args when a list of arguments can be used?

Would passing in a list or dictionary of variables be more concise than passing in *args in Python methods?
For example,
def function(a, *argv):
print('First variable:', a)
for k in argv:
print('Additional variable:',k)
is the same as
def function(a, list):
print('First variable:', a)
for k in list:
print('Additional variable:',k)
except a list is passed in the second argument. What I think using *args would often do is to cause additional bugs in the program because the argument length only needs to be longer than the mandatory argument length. Would any please explain situations where *args would be really helpful? Thanks
The first function accepts:
function('hello', 'I', 'am', 'a', 'function')
The second one won't. For the second you'd need:
function('hello', ['I', 'am', 'a', 'function'])
In principle, the first one is used when your function can have an arbitrary number of parameters (think: print), while the second one specifies that there's always a second parameter, which is an iterable (not necessarily a list, despite the name)
Passing *args is useful when you have to extract only some (or none) arguments in first level function and then pass others to other inner function without knowing about the details. e.g.
def inner_func(x, y, z, *args, **kwargs):
# do something with x, y, and z
return output
def outer_func(a, b, *args, **kwargs):
# do something with a and b
# pass the rest arguments to inner function without caring about details
output = inner_func(*args, **kwargs)
# do something with output
return
That is a fair ask as to why *args (or **kwargs) is essentially required when a list (or dict) could do the same task. The key reason to that is when a ** caller of a function does not know the number of arguments beforehand**. I'll try to explain this with reference to the particular scenario you have shared.
Lets suppose that we have the below function which finds the sum of all integers passed in. (I'm giving up sum builtin function for demonstration purpose, please bear with me :) )
def do_add(*int_args):
total = 0
for num in int_args:
total += num
return total
And you want to call this for an unknown number of arguments with an unknown number of times.
If in case you need to send a list argument, the do_add function might look like below:
def do_add(int_list):
total = 0
for num in int_list:
total += 0
return total
l1 = [1, 2, 3, 4, ... n] # memory loaded with n int objects
do_add(l1)
l2 = [10, 20, ... n]
do_add(l2)
Firstly, you are loading the memory with an additional list object created just for the sake of function call. Secondly, if you have to add some more items to the list we may need to call another list method such as append or extend.
But if you follow the *args approach, you can avoid creating an extra list and focus only on the function call. If you need to add more arguments you can just add another argument separated by a comma rather than calling append or extend methods.
Assume that you want to call this function n times with 1000 arguments. It will result in n * 1000 new list objects to be created every time. But with the variable arguments approach, you can just call it directly.
do_add(1, 2, 3) # call 1
do_add(10.0, 20.0, 30.0) # call 2
...
do_add(x, y, z, ..., m) # call n

python multiple output variables as input

def function_1(a,b,c,d):
print('{}{}{}{}'.format(a,b,c,d))
return
def function_2():
t=y=u=i= 5
return t,y,u,i
function_1(function_2())
I expect that python would execute function 2 first, and return each t, y, u and i as inputs to function1, but instead I get:
TypeError: function_1() missing 3 required positional arguments: 'b', 'c', and 'd'
I understand that either the output of function2 is in a single object, or it is treating function2 as an input function, instead of executing.
how do I change my code to execute as expected? (each of the output variables from function2 treated as input variables to function1)
You need a splat operator.
function_1(*function_2())
function_2() returns a tuple (5, 5, 5, 5). To pass that as a set of four parameters (rather than one four-element tuple as one parameter), you use the splat operator *
Closely related is this question
This might be a slightly awkward way of doing it, but you can actually pss the function as a parameter itself, and then decompose it!
def function_1(func):
print('{}{}{}{}'.format(*func))
return
def function_2():
t=y=u=i= 5
return t,y,u,i
function_1(function_2())
output:
5555

sqrt() argument after * must be a sequence

First of all, I'm super new to python and I actually search for my problem but the examples were to heavy to understand.
Here is my homework; I need a function which takes two functions as an argument and returns if the results of the two functions are same or not? Basically, it will give either TRUE of FALSE.
For that I wrote:
def f(x,y,z):
k=x(*z)
l=y(*z)
return k == l
The previos code I wrote for single function was working but when I modified it for two function as above, it gives an error as following :
import math
>>> f(math.sqrt,math.cos,5)
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
f(math.sqrt,math.cos,5)
File "D:/Users/karabulut-ug/Desktop/yalanmakinesi.py", line 2, in f
k=x(*z)
TypeError: sqrt() argument after * must be a sequence
>>>
I could not figured it out since the error giving function is normally does not take a sequence. So I dont think it makes a sense :) Any help is appreciated.. Thanks :)
z is just a single number, but the * argument expansion syntax requires that you pass in a sequence (like a list, tuple or str, for example).
Either remove the * (and make your function work for just single arguments), or use *z in the function signature to make z a tuple of 0 or more captured arguments:
def f(x, y, z):
k = x(z)
l = y(z)
return k == l
or
def f(x, y, *z):
k = x(*z)
l = y(*z)
return k == l
The latter now works for functions with more than one argument too:
f(math.pow, math.log, 10, 10)
If you added a **kw argument to the signature, then keyword arguments could be handled too:
def f(x, y, *args, **kwargs):
k = x(*args, **kwargs)
l = y(*args, **kwargs)
return k == l
Here I renamed z to args to better reflect its purpose.
The syntax *z invokes argument unpacking on z. When z is just an integer, there is no iterator behavior defined, and so you see this error. Try:
>>> f(math.sqrt, math.cos, [5])
You need to remove the *. Its for unpacking. So:
def f(x,y,z):
k=x(z)
l=y(z)
return k == l
You use the * operator when you want to pass in an iterable object, like a list or tuple as something thats split up. So, for example:
a = [1,2,3,4,5]
So, for an arbitrary function, f:
f(*a) = f(1,2,3,4,5)

Python functions within lists

So today in computer science I asked about using a function as a variable. For example, I can create a function, such as returnMe(i) and make an array that will be used to call it. Like h = [help,returnMe] and then I can say h1 and it would call returnMe("Bob"). Sorry I was a little excited about this. My question is is there a way of calling like h.append(def function) and define a function that only exists in the array?
EDIT:
Here Is some code that I wrote with this!
So I just finished an awesome FizzBuzz with this solution thank you so much again! Here's that code as an example:
funct = []
s = ""
def newFunct(str, num):
return (lambda x: str if(x%num==0) else "")
funct.append(newFunct("Fizz",3))
funct.append(newFunct("Buzz",5))
for x in range(1,101):
for oper in funct:
s += oper(x)
s += ":"+str(x)+"\n"
print s
You can create anonymous functions using the lambda keyword.
def func(x,keyword='bar'):
return (x,keyword)
is roughly equivalent to:
func = lambda x,keyword='bar':(x,keyword)
So, if you want to create a list with functions in it:
my_list = [lambda x:x**2,lambda x:x**3]
print my_list[0](2) #4
print my_list[1](2) #8
Not really in Python. As mgilson shows, you can do this with trivial functions, but they can only contain expressions, not statements, so are very limited (you can't assign to a variable, for example).
This is of course supported in other languages: in Javascript, for example, creating substantial anonymous functions and passing them around is a very idiomatic thing to do.
You can create the functions in the original scope, assign them to the array and then delete them from their original scope. Thus, you can indeed call them from the array but not as a local variable. I am not sure if this meets your requirements.
#! /usr/bin/python3.2
def a (x): print (x * 2)
def b (x): print (x ** 2)
l = [a, b]
del a
del b
l [0] (3) #works
l [1] (3) #works
a (3) #fails epicly
You can create a list of lambda functions to increment by every number from 0 to 9 like so:
increment = [(lambda arg: (lambda x: arg + x))(i) for i in range(10)]
increment[0](1) #returns 1
increment[9](10) #returns 19
Side Note:
I think it's also important to note that this (function pointers not lambdas) is somewhat like how python holds methods in most classes, except instead of a list, it's a dictionary with function names pointing to the functions. In many but not all cases instance.func(args) is equivalent to instance.__dict__['func'](args) or type(class).__dict__['func'](args)

optional arguments function

I am searching how I could use optional arguments in python.
I have read this question but it is not clear to me.
Lets say I have a function f that can take 1 or more arguments to understand time series. Am i obliged to specify the number of arguments and set default values for each argument?
What I aim to do is being able to write a function this way:
simple function:
def f(x,y):
return x + y
#f(1,2) returns 3
What i want is also f(1,2,3) to return me 6 and f(7) returning me 7
Is it possible to write it without setting a predefined number of mandatory/optional parameters?
Is it possible to write it without having to set default values to 0 ?
How to write this function?
Its a simple example with numbers but the function i need to write is comparing a set of successive objects. After comparison is done, the data set will feed a neural network.
Thanks for reading.
EDIT:
Objects I am feeding my function with are tuples like this (float,float,float,bool,string)
You can put *args in your function and then take arbitrary (non-keyword) arguments. *args is a tuple, so you can iterate over it like any Python tuple/list/iterable. IE:
def f(*args):
theSum = 0
for arg in args:
theSum += arg
return theSum
print f(1,2,3,4)
def f(*args):
"""
>>> f(1, 2)
3
>>> f(7)
7
>>> f(1, 2, 3)
6
>>> f(1, 2, 3, 4, 5, 6)
21
"""
return sum(args)
If you need to do something more complicated than sum you could just iterate over args like this:
def f(*args):
r = 0
for arg in args:
r += arg
return r
See this question for more information on *args and **kwargs
Also see this sections on the Python tutorial: Arbitray Argument List
You can use the follow syntax:
def f(*args):
return sum(args)
The * before args tells it to "swallow up" all arguments, makng args a tuple. You can also mix this form with standard arguments, as long as the *args goes last. For example:
def g(a,b,*args):
return a * b * sum(args)
The first example uses the built-in sum function to total up the arguments. sum takes a sequence as adds it up for you:
>>> sum([1,3,5])
9
>>> sum(range(100))
4950
The args name is not mandatory but is used by convention so best to stick with it. There is also **kwargs for undefined keyword arguments.

Categories