Passing a list as arguments to function python - python

Scenario: I am trying to pass a list of strings to a function, as variable inputs.
Issue: Since the variables in the list are just for one of the arguments, I get the error must be str, not list.
The function hakes three inputs as arguments:
transformfile(path, name, id)
I have a list of names I want to pass:
list_names =['Name1', 'Name2', 'Name3']
I tried passing it directly, but got the aforementioned error...
transformfile(path, list_names, id)
Objective: In this case, my objective would be to make the function run multiple times, for each of the names in list_names.
Question: Is it possible to do this kind of procedure, or do I have to simply call the function directly multiple times?

The function isn't made to receive multiple names, it can only handle single names and there is no way to call it that will change that.
Luckily, this is exactly what for loops are for:
for name in list_names:
transformfile(path, name, id)
This is perfectly fine, normal, etc. Even if the function could receive a list, it'd probably have a for loop internally to do that.

You could also use list comprehensions if transformFile returns something:
result = [transformfile(path, n, id) for n in list_names]
Or even map builtin function with or without functools.partial:
result = map(lambda n: transformFile(path, n, id), list_names)
from functools import partial
result = map(partial(path=path, id=id), list_names)
Note: map returns an iterable so, if you want the result of each call, you need to create a list: list(result)

Related

Can you call/use a function returned from a list in Python?

I'm trying to store a function in a list, retrieve the function from the list later, and then call on that function. This is basically what I want to do, without any specifics. It doesn't show my purpose, but it's the same issue.
elements: list = [] # List meant to contain a tuple with the name of the item and the function of the item.
def quit_code():
exit()
element.append(("quit", quit_code))
Now, somewhere else in the code, I want to be able to use an if statement to check the name of the item and, if it's the right one at that time, run the function.
user_input = "quit" # For brevity, I'm just writing this. Let's just imagine the user actually typed this.
if elements[0][0] == user_input:
#This is the part I don't understand so I'm just going to make up some syntax.
run_method(elements[0][1])
The method run_method that I arbitrarily made is the issue. I need a way to run the method returned by elements[0][1], which is the quit_code method. I don't need an alternative solution to this example because I just made it up to display what I want to do. If I have a function or object that contains a function, how can I run that function.
(In the most simplified way I can word it) If I have object_a (for me it's a tuple) that contains str_1 and fun_b, how can I run fun_b from the object.
To expand on this a little more, the reason I can't just directly call the function is because in my program, the function gets put into the tuple via user input and is created locally and then stored in the tuple.
__list_of_stuff: list = []
def add_to_list(name, function):
__list_of_stuff.append((name, function))
And then somewhere else
def example_init_method():
def stop_code():
exit()
add_to_list("QUIT", stop_code())
Now notice that I can't access the stop_code method anywhere else in the code unless I use it through the __list_of_stuff object.
Finally, It would be nice to not have to make a function for the input. By this, I mean directly inserting code into the parameter without creating a local function like stop_code. I don't know how to do this though.
Python treats functions as first-class citizens. As such, you can do things like:
def some_function():
# do something
pass
x = some_function
x()
Since you are storing functions and binding each function with a word (key), the best approach would be a dictionary. Your example could be like this:
def quit_code():
exit()
operations = dict(quit=quit_code)
operations['quit']()
A dictionary relates a value with a key. The only rule is the key must be immutable. That means numbers, strings, tuples and other immutable objects.
To create a dictionary, you can use { and }. And to get a value by its key, use [ and ]:
my_dictionary = { 'a' : 1, 'b' : 10 }
print(my_dictionary['a']) # It will print 1
You can also create a dictionary with dict, like so:
my_dictionary = dict(a=1, b=10)
However this only works for string keys.
But considering you are using quit_code to encapsulate the exit call, why not using exit directly?
operations = dict(quit=exit)
operations['quit']()
If dictionaries aren't an option, you could still use lists and tuples:
operations = [('quit',exit)]
for key, fun in operations:
if key == 'quit':
fun()

Using reduce to iterate over list of functions and call each one

Currently i'm using a list of strings with names of functions to fix the flow of my software:
flow = [
"func1",
"func2",
"func3",
"func4",
"func5"
]
Then i iterate over the flow and call each one passing the options:
options = {}
[getattr(__import__(phase), phase)(options) for phase in flow]
I would like to know if is it possible to do the same, but avoiding side effects, using reduce. Currently, this approach it's making the functions receive the option, but isn't necessary return the options for the next function, so i'm changing the options that is declared in other scope.
Thanks.
You can use functools.reduce (which is sometimes called fold in other functional programming languages like Haskell) to indeed call the function.
In that case however you will need to define a function taking two parameters: the old accumulator value and the element itself. You simply ignore the old value and call the function on the element.
So for a generic function f(x), you can do this with:
functools.reduce(lambda _,x:f(x),list,initializer=0)
So in your case that would be:
options = {}
functools.reduce(lambda _,phase:getattr(__import__(phase),phase)(options),flow,initializer=0)
EDIT:
after rereading your question, it appears to me that each of the functions takes as input options, and generates the "new" options that should be passed to the next function. Well the return of the first function, is the first parameter of the lambda of the next function. So you can fold it together like:
first_options = {}
functools.reduce(lambda options,phase:getattr(__import__(phase),phase)(options),flow,initializer=first_options)
This will result in something equivalent to:
options_0 = first_options
options_1 = getattr(__import__(phase),flow[0])(options_0)
options_2 = getattr(__import__(phase),flow[1])(options_1)
# ...
return options_n
but of course this happens inside the reduce.
so reduce takes one a function, say reduce_func, that takes on 2 arguments. When it goes through a list it takes the first two items as the params of reduce_func for the first call, then on each subsequent call, uses the return value as the first param, and the next value on the list as the second param. This means, for you, reduce_func needs to be the following
def reduce_func(param, f):
return f(param)
and your list needs to be the following:
[options, func1, func2, func3, func4]
Now, I used a list of functions and didn't use import. In stead of f, you could pass in [module].[function] as a string (call the param something like func_str), and do some splitting and inside of reduce_func as some set up.

empty function object in python

I've heard that python functions are objects, similar to lists or dictionaries, etc. However, what would be a similar way of performing this type of action with a function?
# Assigning empty list to 'a'
a = list()
# Assigning empty function to 'a'
a = lambda: pass
# ???
How would you do this? Further, is it necessary or proper?
Here is the sense in which I would like to use it for better context:
I have a QListWidget for selecting items which are associated with keys in a dictionary. The values in this dictionary are also dictionaries, which hold certain properties of the items, which I can add. These certain properties are stored as keys, and the values in them are initialized or updated by calling different functions. So, I'm storing a variable in the window which gets updated when a button is pressed to tell this script which property to update.
As you can see, I would like to store the function to map to the data using the correct function based on the situation.
# Get selection from the list
name = selected_item
# Initialize an empty function
f = lambda: pass
# Use property that is being added now, which was updated by the specific button that was pushed
property_list = items[name][self.property_currently_being_added]
if self.property_currently_being_added == "prop1":
f = make_property1()
elif self.property_currently_being_added == "prop2":
f = make_property2()
elif self.property_currently_being_added == "prop3":
f = make_property3()
elif self.property_currently_being_added == "prop4":
f = make_property4()
# map the certain function to the data which was retrieved earlier
added_property = map(f, data)
property_list.append(added_property)
First, the reason this doesn't work:
a = lamdba: pass
… is that lambda only allows an expression, and defines a function that returns the value of the expression. Since pass is a statement, not an expression, this is illegal.
However, this works just fine:
a = lambda: None
In Python, a function that falls off the end without a return statement always returns None. So, these are equivalent:
def a(): return None
def a(): pass
However, I don't see why you want to write this as a lambda and an assignment anyway; the def is shorter, and more readable, and gives you an introspectable function object with a nice name (a instead of <lambda>), and so on. The only reasons to ever use lambda are when you don't want to give the function a name, or when you need to define the function inside an expression. Obviously neither of those are true, because you use the lambda directly inside an assignment statement. So, just use def.
Meanwhile, this is in a sense an "empty function", or at least as empty as possible (as you can see by, e.g., calling dis.dis(a), it still takes two bytecodes to do nothing but fall off the end and return None), but it's not useful for your case. You don't want an "empty function". If you try passing your a to map, you're just going to get a TypeError, because you're trying to call a function of no arguments with one argument. (Because that's what map does.)
What you might want is an identity function, which just returns its argument as-is. Like this:
def a(x): return x
But I'm not sure that's what you want. Did you want to append data as-is in that case? Or did you want to do something different, like return early, or raise an exception, or not append anything, or …?
Finally, I don't see why you want a function at all. Why not just not call map if you have nothing to map? You have a perfectly good else clause that already catches that case (especially handy if what you want to do is return early or raise…). Or, if you prefer, you can start with f = None, and then use an if f: do decide whether to map or not. Or, if you really want:
added_property = [f(element) if f else element for element in data]
… or …
added_property = map(f, data) if f else data
As one last note, instead of a long if/elif chain that repeats the same thing over and over again, you might want a dict:
propfuncs = {'prop1': make_property1(),
'prop2': make_property2(),
'prop3': make_property3(),
'prop4': make_property4()}
Then, all that cruft turns into these two lines:
f = propfuncs.get(self.property_currently_being_added)
added_property = map(f, data) if f else data
Or course an even better design might be to replace all those make_propertyN functions with a single function that you call as make_property(1) or make_property('prop1')… but without seeing what they actually do, I can't be sure of that.
For completeness and since the title is "empty function object in python", more general case is an empty function object that takes any number of parameters, so you can use it in any callback. It's this one:
callback = lambda *_, **__: None
Explanation is here: http://echochamber.me/viewtopic.php?t=64825
I am surprised to learn that you can even do...
def a(): "This is a test"
a()
this feels so much like you're looking for a Nothing functor, I am guessing that if you had knowledge of Monads you wouldn't even need an empty function , as inspiration PyMonad has a nice Nothing implementation, I usually like to create my own, but it's a good starting point.

How to use all the dynamic input recursively with a dynamic function in python?

I will explain the example since its easer to describe that way:
Say we have an undetermined (X) number of variables that can be either lists or strings.
For the example, X=3, and we have:
Var1=list("a","b")
Var2=list("c","d")
Var3="e"
And all of those are together in a list:
ListOfVariables=[Var1,Var2,Var3]
Then we have a function (we dont know this function in advance, but it uses the same number X of variables that we have) that runs on those variables.
def Function(Var1,Var2,Var3)
print Var1
print Var2
print Var3
The objective here is to make the Function run with all the input variables, and in case one of those is a list, it must do the Function for each item of the list. So the wanted result would be to call Function for all of them, like this:
Function(a,c,e)
Function(a,d,e)
Function(b,c,e)
Function(b,d,e)
So far, Im using a helper function that will identify Var1,Var2, and Var3, but my brain doesnt have so much recursion predictability as to be able to define this HelperFunction such as:
def HelperFunction():
for item in ListOfVariables:
if type(item).__name__=='list':
#This one will be done as a "for", so all the items in this list are executed as input (Var1 and Var2 in the example)
else:
#This item doesnt need to be included in a for, just execute once (Var3 in the example)
I know it can be done with python, but I cant program in my mind the function that I need, its one degree of complexity more than my "brain emulator" can emulate python =(
Thank you very much for your help.
EDIT AFTER ANSWERS:
Thank you very much for the answers, but Im not sure if the proposed solution solves the problem.
If we run:
helper_function(ListOfVariables)
Then helper_function should call the function "Function" 4 times, like this:
Function(a,c,e)
Function(a,d,e)
Function(b,c,e)
Function(b,d,e)
The intention is to use all the variables in the input, BUT in their corresponding place within the Function needs.
More specifically, the logic process for the helper_function(ListOfVariables) is:
Var1 is a list, therefore, I will have to loop through its contains and run Function() with those, but those will ONLY be the first argument of the function!
Var2 is a list, therefore, I will also loop, with the items being ONLY the second argument of the Function()
Var3 is a single item, therefore, for the other two loops, this value will be assigned constant.
That is how we get the desired:
Function(a,c,e)
Function(a,d,e)
Function(b,c,e)
Function(b,d,e)
Thank you very much, I just cant figure this out myself!
If I'm understanding you correctly, then to generalize the problem further: you want to iterate the function on the product of all the elements within the arguments; non-list arguments should be treated as lists that contain only themselves. Using the itertools module, and treating this as an iterative rather than recursive process simplifies things:
import itertools
def combine(*args):
lists = [arg if isinstance(arg, list) else [arg] for arg in args]
for a, b, c in itertools.product(*lists):
Function(a, b, c)
Var1=["a","b"]
Var2=["c","d"]
Var3="e"
combine(Var1, Var2, Var3)
If you need to handle lists-of-lists, then you need a recursive process.
Is this broadly what you're looking for?
def helper_function(my_list):
for item in my_list:
if isinstance(item, basestring):
do_something(item)
else:
helper_function(item)
If the item in the list is a string, then you run your function against it. If it isn't then you just call the helper function again on the item, since it accepts any arbitrary list containing strings.
If I understand you correctly, you don't know how many arguments to expect and you wish to run a function on them nevertheless. If so, you want to use the * to define an unknown amount of args that will be treated as a list. Then it's simply a conditions, like so:
def some_name(*args):
for arg in args:
if isinstance(arg, list):
some_name(*arg)
if isinstance(arg, str):
print arg
Is that it?
def recurse_me(my_list):
if not isinstance(my_list,(list,tuple)):
print "Unexpected Arg! not a list!!:",my_list
for item in my_list:
if isinstance(item,(list,tuple)):
print "Recursive Call! recurse_me(%s)"%item
recurse_me(item)
else:
print "Normal:",item
not sure if this is what you wanted but I think so
Why don't use the arguments directly?
def func(*vars):
for var in vars:
dostuff_with_var(var)
In dostuff_with_var you can check the type and act accordingly.

Why would unpacking be preffered over passing in a list

Unpacking argument lists:
def send(*data):
for datum in data:
ser.write(datum)
vs sending in a list in the first place:
def send(data):
for datum in data:
ser.write(datum)
When it simplifies the API for the case where otherwise you'll always have to pass in a list:
send(something, otherthing)
versus:
send([something, otherthing])
where your usual parameters are taken from different locations; e.g. something and otherthing are more likely to be separate variables than already collected in one list.
The Python 3.x print() function does exactly that, as well as the os.path.join() function. You rarely have all your print arguments or path-elements-to-join combined in a list before calling the API.
Compare:
os.path.join(rootdirectory, relativepath, filename)
print('Debug information:', localvariable)
vs.
os.path.join([rootdirectory, relativepath, filename])
print(['Debug information:', localvariable])
If .join() or print() were to accept only one positional argument (a list), the users of the API would find themselves typing the [ and ] brackets over and over again.
By accepting a variable number of positional arguments, you save users of your API the trouble of having to create list just for the function call. In the rare cases where the parameters have already been collected into a list, they can use the *params calling convention:
send(*params)
to echo your function signature.

Categories

Resources