Handle differing number of returned variables - python

I am looking for handling differing number of returned values from invoked functions in a set number of target variables. The following simplified snippet is a starting illustration:
def f1(): return 1,2,3
def f2(): return 4,5
a,b,c = f1()
a,b,c = f2() # How to massage this call: default of some sort?
So the objective would be to unpack either 2 or 3 results into three output variables.
Consider that the f() being invoked may be one of (many functions..) that mostly all return only two variables .. but there is a need to add a third parameter to maybe one or two of them.
The motivation here: an existing codebase that presently returns only two variables. But I need to add a third one. It would be helpful to leave the existing code mostly alone and simply handle the missing third parameter gracefully.
What construction could be used here?

Generally, you could save all of the returned values to a single variable and then access them using indexing.
x1 = f1() # x1[0] = 1, x1[2] = 2, etc.
x2 = f2()
For Python 3:
If you need to use a,b,c for separate pieces of code, you can pack the variables using:
a,b,*c = f1()
a,b,*c = f2()
This will capture all values beyond the first 2 returned by f1 or f2 as a list in c.
Any python:
If you are in version 2.7, you can take a few extra steps to ensure assigning c doesn't give an error. You capture the output of your function as a list, then extend the list to the length of your variables using None. After that, you can assign directly to a,b,c
# assumes you have 3 variables: a,b,c
res = list(f2())
res += [None]*(3-len(res))
a,b,c = res

You are unpacking the result of those two functions, instead of doing that perhaps you could assign the result to a single variable then test that for length. much like here: ValueError: need more than 2 values to unpack in Python 2.6.6
t = list(f2())
if len(t) > 2:
# Can use the third result!
c = t[2]

Related

Inputting list elements into function

I was wondering if there is a way to take the elements in a list and insert them into the inputs of a function. So for example
def function(x,y,z):
#does stuff
def main():
changing_list=[8,9,10]
function(changing_list)
I am using the function GetRows in Spotfire, which allows different amounts of input to be used. So I am planning to put the names of rows I am going to use into the list and then use it to give the inputs into the function. If there is a better way of doing this please tell me, I can't put in the inputs before hand due to me not knowing which rows I will be using beforehand. If there is something unclear please ask me to clarify. An important point that I noticed that I may have left out after looking at the answers. I cannot adjust the code in the function due to me not have access to it. Also the function might not always accept 3 inputs, it will vary depending on the what happens when the code runs before hand, the list may have 5 elements in one run and 1 element in the next one.
Change the line of:
function(changing_list)
To:
function(*changing_list)
If you're in Python 3.
Use:
function(l[0], l[1], l[2])
For this you can use the single star * which unpacks the sequence. This allows you to do this:
def mul(x, y):
return x * y
nums = (1, 5)
s = mul(*nums)
This will unpack the tuple. It actually executes as:
s = mul(1, 5)
You have requested 3 variables for your function when defining it, but you only give it one list. Try this:
def function(xs):
xs[0] = 1
xs[1] = 2
xs[2] = 3
def main():
changing_list = [8, 9, 10]
function(changing_list)
Now your function will take your list, and change it to [1, 2, 3]. You can use print to check.

Python append to list from return tuple

I have a list and a function f which returns a 3-tuple. I would like to capture the first two return values, and with the third, append to lst. I know I can do the following:
a, b, c = f()
lst.append(c)
but I would like a way not to have the extraneous variable "c". I know I can also do:
lst.append(f()[2])
but I do not want to throw away the other two return values.
Any suggestions?
Edit: I appreciate the answers provided, but the question, put more clearly, is to find a neat one-liner.
Assign the return value to a local variable before you append the result.
No, you can't catch two values and append the third in one statement; you only get one "verb" per command.
result = f()
lst.append(result[2])
What you want to do is not possible with a "one liner" (without using semi-colon to fit two statements on a single line) unless you change your function definition.
Specifically, define f() in the following way:
def f(list_to_append_to):
a = ...
b = ...
c = ...
list_to_append_to.append(c)
return a, b
Then:
a, b = f(mylist)
If your problem is not saving yourself with writing one more line of code, but you would just want the function call, the assignment and the appendix in a single statement, you could use a wrapper function:
def append_and_assign(mylist, myfunc):
a, b, c = myfunc()
mylist.append(c)
return a,b,c
and so you can call:
a,b,c = append_and_assign(lst, f)

Check the number of parameters passed in Python function

I'm new in Python and wants to know if there is a simple way to get amount of passed parameters in Python function.
a(1, 2, 3) ==>3
a(1, 2) ==>2
def a(*args, **kwargs):
print(len(args) + len(kwargs))
You can do this by using locals()
It is important to note, that this should be done as ultimately, your first step in your method. If you introduce a new variable in your method, you will change your results. So make sure you follow it this way:
def a(a, b, c):
# make this your first statement
print(len(locals()))
If you did this:
def a(a, b, c):
z = 5
print(len(locals()))
You would end up getting 4, which would not be right for your expected results.
Documentation on locals()
you could also change the input for your function to a list, so to have a function:
a(your_list)
then to know how many arguments have been passed to the function,
you could simply do:
print len(your_list)
However, this means that you change the input type for your function,
from many input variables to only one, the list(which can have a variable number of elements).

python: proper use of dictionaries

i try to create a function, which generates random int-values and after a value appeared twice the function should return the number of all generated int-values.
I have to use a dictionary.
This is my code so far:
def repeat(a,b):
dict={}
d=b-a+2
for c in range(1,d):
dict['c']=random.randint(a,b)
for f in dict:
if dict['f']==dict['c']:
return c
First problem: It doesn't work.
>>> repeat(1,5)
Traceback (most recent call last):
File "<pyshell#144>", line 1, in <module>
repeat(1,5)
File "<pyshell#143>", line 7, in repeat
if dict['f']==dict['c']:
KeyError: 'f'
Second problem: if dict['f']==dict['c']:
Should be true in first step because both values are the same.
I can't find a smart way to compare all values without comparing a key with itself.
Sorry for my bad english, it's kinda rusty and thank you for your time.
Enclosing your variable names in quotes makes them strings - Python is looking for the key of the letter f, not the key with the integer in the f variable.
Simply use the variable normally and it should work as you expected:
def repeat(a, b):
stored = {}
d = b - a + 2
for c in range(1, d):
stored[c] = random.randint(a, b)
for f in stored:
if stored[f] == stored[c]:
return c
Note also that you are shadowing the built-in function dict() by naming your variable dict - it is preferable to use another name because of this.
This isn't really an answer to your question. #Lattyware told you the problem. But I can't put code in a comment so I'm posting this as an answer.
Your code is using weird variable names, which makes the code harder to understand. I suggest you use variable names that help the reader to understand the program.
I've changed your variable names and added comments. I also put in a "doc string" but I don't really understand this function so I didn't actually write a documentation message.
def repeat(a,b): # short names are okay for a,b as they are just two numbers
"""
This is the "doc string". You should put in here a short summary of what the function
does. I won't write one because I don't understand what you are trying to do.
"""
# do not use built-in names from Python as variable names! So don't use "dict"
# I often use "d" as a short name for a dictionary if there is only one dictionary.
# However, I like #Lattyware's name "stored" so I will use it as well.
stored={}
# You only used "d" once, and it's the upper bound of a range; might as well just
# put the upper bound inside the call to range(). If the calculation was really long
# and difficult I might still use the variable, but this calculation is simple.
# I guess you can use "c" in the loop, but usually I use "n" for number if the loop
# is making a series of numbers to use. If it is making a series of indexes I use "i".
for n in range(1,b-a+2):
stored[n]=random.randint(a,b)
# Any for loop that loops over a dictionary is looping over the keys.
for key in stored:
# I don't understand what you are trying to do. This loop will always terminate
# the first time through (when n == 1). The line above this for loop assigns
# a value to stored[n], and n will be equal to 1 on the first loop; then this
# test will trivially succeed.
if stored[key] == stored[n]:
return n

Multiple return values in python

I want to change a python function to return two values. How do I achieve that without affecting any of the previous function calls which only expect one return value?
For eg.
Original Definition:
def foo():
x = 2
y = 2
return (x+y)
sum = foo()
Ne Definition:
def foo():
x = 2
y = 2
return (x+y), (x-y)
sum, diff = foo()
I want to do this in a way that the previous call to foo also remains valid?
Is this possible?
def foo(return_2nd=False):
x = 2
y = 2
return (x+y) if not return_2nd else (x+y),(x-y)
then call new version
sum, diff = foo(True)
sum = foo() #old calls still just get sum
By changing the type of return value you are changing the "contract" between this function and any code that calls it. So you probably should change the code that calls it.
However, you could add an optional argument that when set will return the new type. Such a change would preserve the old contract and allow you to have a new one as well. Although it is weird having different kinds of return types. At that point it would probably be cleaner to just create a new function entirely, or fix the calling code as well.
I'm sorry to tell you, but function overloading is not valid in Python. Because Python does not do type-enforcement, multiple definitions of foo results in the last valid one being used. One common solution is to define multiple functions, or to add a parameter in the function as a flag (which you would need to implement yourself)

Categories

Resources