Best Way to Pass Arguments from One Function to Another in Python - python-3.x

I have a function that performs a specific task, and this function takes many options, both named and unnamed options. For example:
def eat_fruit(x,a_number=None , a_fruit=None):
return(f'{x} ate {str(a_number)} {a_fruit}')
#call the function
eat_fruit("John",a_number=5,a_fruit='apples') #outputs 'John ate 5 apples'
Now, I have another function that takes many options, for example:
def do_lots_of_stuff(a,b,activity_1=None,activity_2=None):
return(f'''{a} and {b} {activity_1} and {activity_2}''')
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump') #returns "Bob and Mary run and jump"
I want to have the function do_lots_of_stuff call the function eat_fruit, sometimes with options. However, it is not clear to me how to pass options from one to the other in a straightforward manner.
Ideally, I am looking for something like:
#This code does not work; it demos the type of functionality I am looking for.
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump', eat_fruit_options={*put_options_here*}):
eat_fruit(eat_fruit_options)
return(f'''{a} and {b} {activity_1} and {activity_2}''')
Note that this can't be accomplished via do_lots_of_stuff(*do_lots_of_stuff_options*, *eat_fruit_options*) since options for eat_fruit are not valid do_lots_of_stuff options. Furthermore, keyword arguments must come after positional arguments. In addition this solution does not seem to be sufficient here, because I only want to pass some arguments, not all of them.
Other relevant links (although I don't believe they successfully address my question):
can I pass all positional arguments from one function to another in python?
Passing variables between functions in Python
Passing value from one function to another in Python

do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump', eat_fruit_args=["John"], eat_fruit_kwargs={"a_number": 5, "a_fruit": "apples"}):
eat_fruit(*eat_fruit_args, **eat_fruit_kwargs)
return(f'''{a} and {b} {activity_1} and {activity_2}''')
You can pass and forward arguments and keyword arguments. Arguments are in the form of a list. Keyword arguments (kwargs) are in the form of a dictionary, with the key as a string, and the value as the correlating keyword value.

Related

Passing one list instead of two in python

Here I have written a function which takes two lists as argument. But when I called this function passing one list as argument, it works well! Why is this working? Here name_function has two arguments but I passed only one list as argument.
def name_function(names=list(),_list=list()):
for name in names:
_list.append(name)
return _list
print(name_function(['mike','smith','bob']))
Here in the function definition you have initialized both the
arguments with the empty list i.e. you are using two default
arguments in the function definition.
For the above reason the function call works if you provide provide
both the arguments or any one of the arguments or no argument at
all.
To learn more about default arguments in python you can refer this
link or this link.

How to initilise a list that contains custom functions without python running those functions during initialisation?

Short version:
How do you store functions in a list and only have them be executed when they are called using their index position in the list?
Long Version:
So I am writing a program that rolls a user-chosen number of six-sided dice, stores the results in a list and then organizes the results/ data in a dictionary.
After the data is gathered the program gives the user options from 0-2 to choose from and asks the user to type a number corresponding to the option they want.
After this input by the user, a variable, lets say TT, is assigned to it. I want the program to use TT to identify which function to run that is contained within a list called "Executable_options" by using TT as the index posistion of this function within the list.
The problem I am having is that I have to have the list that contains the functions on a line after the functions have been defined and when I initialize the list it goes through and executes all functions within it in order when I don't want it to. I just want them to be in the list for calling at a later date.
I tried to initialise the list without any functions in and then append the functions individually, but every time a function is appened to the list it is also executed.
def results():
def Rolling_thunder():
def roll_again():
The functions contains things, but is unnecessary to show for the question at hand
Executable_options = []
Executable_options.append(results())
Executable_options.append(Rolling_thunder())
Executable_options.append(roll_again)
options = len(Executable_options)
I am relatively new to Python so I am still getting my head around it. I have tried searching for the answer to this on existing posts, but couldn't find anything so I assume I am just using the wrong key words in my search.
Thank you very much for taking the time to read this and for the answers provided.
Edit: Code now works
The () on the end of the function name calls it - i.e. results() is the call to the results method.
Simply append to the list without the call - i.e:
Executable_options.append(results)
You can then call it by doing e.g.:
Executable_options[0]()
as per your given data the code will look like this:
def results():
def Rolling_thunder():
def roll_again():
Executable_options = []
Executable_options.append(results)
Executable_options.append(Rolling_thunder)
Executable_options.append(roll_again)
for i in range(0,len(Executable_options)):
Executable_options[i]()
this will work for you.

Embeded arguments with Kwargs

Is there a way to have embedded arguments, and pass kwargs to the function?
For example:
Robot file
Testcase1
do something "value" extra_args=bla
Python library
#keyword('do something "${value}"')
def do_something(self, value, **kwargs):
print(value)
print(kwargs)
Though the above way does not work. I've also tried with
Testcase1
do something "value" extra_args=bla
Also
*** Variables ***
&{DICT} extra_args=bla
Testcase1
do something "value" &{DICT}
And many other combinations. I've found pull request in Robotframework where this limitation was added, but I am sure other Library writers must want this feature.
Thanks
Short answer - no, that is not allowed; doc link, the last paragraph in Basic Syntax.
Thinking about it, I can see where does this limitation come from - if kwargs were supported in keywords with embedded arguments, the parser would have very hard time, mainly in two regards:
Where to break up the arguments as separate variables?
In this sample code:
My keyword #{kwarg} varies
Pass Execution
, when called like this:
My keyword was called varies
, what should the arguments be - one with value was called, or two - was and called?
Matching the target keyword
Another sample keywords definition:
My keyword #{kwarg}
Pass Execution
My keyword ${normal} argument
Pass Execution
, when called like this:
My keyword one argument
, which of the two keywords should the parser match?
As you can see kwargs in the embedded syntax would cause problems, and this is probably only the tip of the iceberg.
Side note - though I personally find keywords with embedded arguments mega cool - you can have calls that look like plain English! almost no other language gives you this possibility!, with practice I have found them limiting, and now try to avoid them.
Two reasons - you cannot change the signature of such keyword in the future, e.g. add optional arguments (or kwargs ;)). The second is the arguments are always passed on as string objects - so you'll have to cast them in the keyword if it deals with another type, and forget about ever passing complex object types.
In the Robot Framework documentation this is described in section Free keyword arguments (**kwargs).
Robot Framework 2.8 added the support for free keyword arguments using
Python's **kwargs syntax. How to use the syntax in the test data is
discussed in Free keyword arguments section under Creating test cases.
In this section we take a look at how to actually use it in custom
test libraries.
This is the Python example:
def various_args(arg, *varargs, **kwargs):
print 'arg:', arg
for value in varargs:
print 'vararg:', value
for name, value in sorted(kwargs.items()):
print 'kwarg:', name, value
and the corresponding Robot File:
*** Test Cases ***
Positional
Various Args hello world # Logs 'arg: hello' and 'vararg: world'.
Named
Various Args arg=value # Logs 'arg: value'.
Kwargs
Various Args a=1 b=2 c=3 # Logs 'kwarg: a 1', 'kwarg: b 2' and 'kwarg: c 3'.
Various Args c=3 a=1 b=2 # Same as above. Order does not matter.
Positional and kwargs
Various Args 1 2 kw=3 # Logs 'arg: 1', 'vararg: 2' and 'kwarg: kw 3'.
Named and kwargs
Various Args arg=value hello=world # Logs 'arg: value' and 'kwarg: hello world'.
Various Args hello=world arg=value # Same as above. Order does not matter.

Lambda commands for tracing tkinter variables [duplicate]

Python has classes for Tkinter variables StringVar(), BooleanVar(), etc. These all share the methods get(), set(string), and trace(mode, callback). The callback function passed as the second argument to trace(mode, callback) is passed four arguments, self, n, m, x.
For an example of a BooleanVar() these appear to be '', 'PYVAR0', 'w'.
The third argument x appears to be the mode that triggered the trace, in my case the variable was changed. However, what is the first variable that appears to be an empty string? What is the second, if I had to guess I'd say some internal name for the variable?
The first argument is the internal variable name. You can use this name as an argument to the tkinter getvar and setvar methods. If you give your variable a name (eg: StringVar(name='foo')) this will be the given name, otherwise it will be a name generated for you by tkinter (eg: PYVAR0)
If the first argument represents a list variable (highly unlikely in tkinter), the second argument will be an index into that list. If it is a scalar variable, the second argument will be the empty string.
The third argument is the operation, useful if you are using the same method for reading, writing and/or deleting the variable. This argument tells you which operation triggered the callback. It will be one of "read", "write", or "unset".
Tkinter is a python wrapper around a tcl/tk interpreter. The definitive documentation for variable traces can be found here: http://tcl.tk/man/tcl8.5/TclCmd/trace.htm#M14. Though, this only documents how the internal trace works, the tkinter wrapper sometimes massages the data.
The first argument is the name of the variable, but is not "useless" since you can set it when you declare the variable, e.g.:
someVar = IntVar(name="Name of someVar")
When you check the first argument in the trace callback it will equal "Name of someVar". Using the name to distinguish between variables, you can then bind the same handler to trace changes to any number of variables, rather than needing a separate handler for each variable.

Can Python use a functions default parameter when an inline if fails when calling it?

If I have a variable that has a value I don't want passed to a function, is it possible to do it without several ifs, especially if there are several variables that may or may not need to be passed in?
Take the following:
def test(param=""):
...do stuff
x = None
test(x if x else ?)
^
What can i put here so it
defaults to the default in
the function definition?
If this isn't possible, is there a quick way of doing this when there are multiple variables that may or may not need to be passed in rather than a lot of ifs?
Basic answer:
if(x): test(x)
else: test()
With *args you can pass in as many variables as you want but I don't think that will help you. The best I can think of is multiple ifs (Python doesn't allow overloading unfortunately).
That would look like:
if x:
if y:
if z: test(x,y,z)
else: test(x,y)
else: test(x)
else: test()
The reason you can't call test(x,z) or test(y) for example is because your method assumes a certain order in the signature so you wouldn't be able to specify which arg you are passing in at function call. In Java you could do it with overloading and different argument types, but not here afaik.

Resources