Passing many variables as one variable in python - python

I have a list of variables that I want to send to my function. (so the function works based on the values on those variables).
One way is to pass each variable separately in the function like this:
def my_function(var1, var2, var3, var4, ..., varn):
output = var1 + var2 + var3 + var4 + .... + varn
However, I wonder if I can write such a thing:
def my_function(parameters):
output = parameters.var1 + parameters.var2 + ... + parameters.varn
That is, somehow is there any way to wrap all variables in one variable, and then call them like this?
I know the above python codes are not correct, I just want to express my question.
Thanks in advance

There are many options. You have to determine which way fits your case.
Option 1. Getting multiple arguments by a single asterisk
def my_function(*args):
output = sum(args)
# SAME WITH
# output = args[0] + args[1] + ... + args[n]
#
# PASSING ARGUMENTS EXAMPLE
# my_function(10, 20, 10, 50)
Option 2. Getting keyword arguments by double asterisk
def my_function(**kwargs):
output = sum(kwargs.values())
# SAME WITH
# output = kwargs["var0"] + kwargs["var1"] + ... + kwargs["varn"]
#
# PASSING ARGUMENTS EXAMPLE
# my_function(var0=10, var1=20, var2=15)
Option 3. Getting an argument as a list
def my_function(list_arg):
output = sum(list_arg)
# SAME WITH
# output = list_arg[0] + list_arg[1] + ... + list_arg[n]
#
# PASSING ARGUMENTS EXAMPLE
# my_function([1, 10, 3, -10])
Option 4. Getting an argument as a dictionary
def my_function(dict_arg):
output = sum(dict_arg.values())
# SAME WITH
# output = kwargs["var0"] + kwargs["var1"] + ... + kwargs["varn"]
#
# PASSING ARGUMENTS EXAMPLE
# my_function({"var0":5, "var1":10, "var2":3})

Related

Optional arguments in nested functions in Python

Is it possible for one function to take as an argument the name of one of the optional arguments of a second function then call the second function with the optional argument set to the value of some variable in the first function?
Code (that obviously doesn't work)
def foo(a=1,b=2,c=3):
d = a + b + c
return d
def bar(variable):
z = get_user_input()
e = foo(variable = z)
return e
print(bar(a))
The desired result is for bar to call foo(a=z) and print whatever z+2+3 is. Of course Python doesn't know what (a) is here. My guess is that I can somehow reference the list of arguments of foo() , but I am stumped as to how you might do that.
Maybe try the code snippet below
def foo(a=1,b=2,c=3):
d = a + b + c
return d
def bar(variable: str):
z = int(input())
e = foo(**{variable: z})
return e
# variable name should be defined as string
print(bar("a"))
The ** parses all arbitrary arguments on dict, in this case is a. Be careful tho, as if passing wrong variable name (differ from a, b or c) will result raising error.

syntax error: non-keyword arg after keyword arg

I'm using Python 2.7.13 in spyder.
def test(a,b,c='c',*args):
for item in args:
print item
This function definition is valid in Python 2.7, but as soon as I try to pass in args it gives me the non-keyword arg after keyword arg error:
test(1,2,c='c',10,11)
Gives this:
non-keyword arg after keyword arg
But this:
test(1,2,3,4,5)
Is working.
I'm not sure what's the issue here since putting the *args bfore c='c'
def test(a,b,*args,c='c'):
for item in args:
print item
This gives me an error in the function definition.
The above code is just a dummy example the original code looks like the following:
def export_plot_as_mat(fname, undersamp, undersamp_type, n_comp, b_s, n_iter, fit_alg, transf_alg, alpha_train, alpha_test, export_info=False, *args):
info = ('undersampling=' + str(undersamp) + ' undersampling_type=' +str(undersamp_type) +
' n_comp=' + str(n_comp) + ' batch_size=' + str(b_s) +
' n_iter=' + str(n_iter) + ' fit_alg=' + str(fit_alg) +
' transform_alg=' + str(transf_alg) + ' alpha_train=' +
str(alpha_train) + ' alpha_test=' + str(alpha_test))
d = [(str(args[i]), args[i]) for i in range(len(args))]
if export_info:
d.append('info',info)
sp.io.savemat(fname + '.mat', d)
I want to have the option to export the parameters used to build the data I'm exporting.
The definition is fine, since c can be specified positionally. The call is the problem; you specified a keyword argument before another positional argument.
Python 2.x doesn't have a way to define keyword-only arguments.
This is an interesting side case of how Python 2.x does argument parsing. Roughly, Python has some logic for how to "match up" the arguments you pass to a function with the arguments that it is expecting, and this logic changed in Python 3.
The easiest way to get what you want is to accept **kwargs instead of specifying c=0, and do the default argument manually.
A couple things here.
When change the c = 'c' in your test() to just 'c'
also u can put your last to arguments in a list to print them on the same line. or leave them as is to print them in separate lines.
def test(a,b,c='c',*args):
for item in args:
print item
test(1,2,'c',[10,11])
result:
[10, 11]
For the argument c = 'c' you can pass anything you want there and interact with c:
Take this example:
def test(a,b,c='c',*args):
print c
for item in args:
print item
test(1,2,'g',10,11)
Result:
g
10
11

Design for application able to calculate a function or load the result from a file

I have many files that I need to process with certain time-consuming functions f_1() ... f_n().
Because of this, I tought to save the fk_processed_output in a file every time a function f_k() ends its work, in order to avoid recalculation in future work sessions.
The program has to be able to choose dynamically if it need to calculate the result or to load it from HDD (if it was calculated in a previous time for the given input file).
What may be a good design to implement this?
I thought to implement every f_k{} like this:
def f_k():
if (fk_processed_output.exist()):
load_it_from_file()
else:
output = do_some_stuff()
save_to_file(output)
but I don't like it very much because of the repetion of the if/else pattern for each function.
Any better or clever idea? Any other hint? Does exist any library for such a purpose?
Use a decorator:
def fk_processed (fk):
filename = fk.__name__ + '_output.json'
def new_fk (*args, **kargs):
if (os.path.exists(filename)):
print("Load from file (" + fk.__name__ + ").")
output = json.load (open(filename))
else:
print("Call to function (" + fk.__name__ + ").")
output = fk (*args, **kargs)
json.dump (output, open(filename, 'w'))
return output
return new_fk
#fk_processed
def f1 ():
...
#fk_processed
def f2 ():
...
>>> f1 ()
Call to function (f1).
>>> f1 ()
Load from file (f1).
I used json for storing data so you don't have (most of the time) to worry about the type of the values returned by the fk.
Note that this does not work if the output of your fk is not always the same. In this case you have to add some extra stuff to fk_processed.
Here is a version that works with arguments but not with keyword arguments (you can modify it if you want, simply always consider keywords arguments in the same order... ). Do not use it if you don't have very heavy function!
def fk_processed (fk):
filename = fk.__name__ + '_output.json'
def new_fk (*args):
store = {}
if (os.path.exists(filename)):
store = json.load (open(filename))
cstore = store
i = 0
while i < len(args) and str(args[i]) in cstore:
cstore = cstore[str(args[i])]
i += 1
if i != len(args):
while i < len(args) - 1:
cstore[str(args[i])] = {}
cstore = cstore[str(args[i])]
i += 1
# print('compute')
cstore[str(args[i])] = fk (*args)
cstore = cstore[str(args[i])]
json.dump (store, open(filename, 'w'))
return cstore
return new_fk
Note that I am converting the arguments to string in the store dictionnary because JSON allows only string as keys. This can break lot of things if your function arguments are not simple.
Example:
>>> #fk_processed
... def add (x, y): return x + y
...
>>> add (1, 2)
compute
3
>>> add (1, 3)
compute
4
>>> add (1, 2)
3
>>> add ('1', '3') # Here is the problem if you can have various types from your arguments
4 # expected '13'

Getting parameter name

I searched about it and got the following, python obtain variable name of argument in a function but i am not getting required answer and am actually getting an error saying add () takes exactly 0 arguments when i used kwargs. So reposted to get an answer if there is any.
i have the following code,
def add ( arg1, arg2):
z = arg1 + arg2
print arg1Name, arg2Name, z
x = 10
y = 5
add( x,y )
i want output as
x y 15
You should use func_code.co_varnames attribute of your function to access parameters names:
def add(arg1, arg2):
z = arg1 + arg2
print ' '.join(add.func_code.co_varnames[:2]) + ' ' + str(z)
add(10, 5)
Output:
arg1 arg2 15
You can read more about internal attributes here:
https://docs.python.org/2/library/inspect.html#types-and-members
I think the closest you can get to what you want is as follows:
def add (**kwargs):
assert len(kwargs) == 2, "Not enough arguments"
keys = kwargs.keys()
z = kwargs[keys[0]] + kwargs[keys[1]]
print keys[0], keys[1], z
x = 10
y = 5
add(x=x,y=y)
add(w=11,t=11)
Results in:
y x 15
t w 22
One liner solution here,**kwargs returns a dict, check that with;
def add(**kwargs):
print (kwargs)
add(x=5,y=10)
>>>
{'y': 10, 'x': 5}
>>>
It's a normal dict. You can reach the each element with basic dict methods.
print (kwargs.keys())
>>>
dict_keys(['y', 'x'])
>>>
Using kwargs is a tradition actually, you can use whatever you want instead of it. Here is the solution,print dict keys and sum of values;
def add(**ChuckNorris): #instead of **kwargs
print (" ".join(ChuckNorris.keys()),sum(list(ChuckNorris.values())))
add(x=5,y=10)
>>>
x y 15
>>>
You can do it using the traceback module.
def get_current_arg_names():
import traceback, re
tb = traceback.extract_stack()
method = tb[-2][2]
func_call = tb[-3][3]
args = re.search('%s\s*\((.*?)\)' % method, func_call).group(1)
return [ x.strip() for x in args.split(',') ]
def add(arg1, arg2):
z = arg1 + arg2
print get_current_arg_names(), z
return z
x = 1
y = 3
print add(x, y)
However the regex would need to be improved and event then, there is a requirement that the function call not be spread across multiple lines.
Better to modify you code if possible as this is messy.

Python named keyword by variable

I'm new to python and I'm trying to figure out if I can pass named keywords by string without calling them explicitly.
Here an example:
def test(height, weight):
print("h=" + str(height))
print("w=" + str(weight))
test(weight=1, height=2) # output
a = "weight"
b = "height"
test(a=1, b=2) # same output
Is this possibile?
Thanks!
Use a dict.
kwargs = {a: 1, b: 2}
test(**kwargs)
Sort of. Try this:
a = "weight"
b = "height"
kwargs = {
a: 1,
b: 2
}
test(**kwargs)
I think the other answers are missing the point. Sure, they are correct answer to the problem you're suggesting, but they're not the answer you're looking for.
I'll condense your code a little to this:
def test(a):
print(a)
test("hello, world!") # Works!. The string is passed to the first paramater, which
# is 'a'.
test(a = "hello, world!") # Works! The 'a' parameter that the function accepts is
# set to "hello, world".
test(b = "hello, world!") # Fails. 'b' does not exist as a parameter in test().
b = "a" # You're trying to set the 'b' keyword to equal the 'a' keyword here.
# This does NOT work, which we'll see in a bit.
test(b = "Hello, world!") # Still fails. The function checks whether 'b' exists
# as a parameter. There is no such parameter.
print(b) # Prints "a". The variable 'b' was NOT changed when test() was called.
# You merely tried to change the parameter 'b' of the function test(),
# which did not exist in the first place.

Categories