python theading.Timer: how to pass argument to the callback? - python

My code:
import threading
def hello(arg, kargs):
print arg
t = threading.Timer(2, hello, "bb")
t.start()
while 1:
pass
The print out put is just:
b
How can I pass a argument to the callback? What does the kargs mean?

Timer takes an array of arguments and a dict of keyword arguments, so you need to pass an array:
import threading
def hello(arg):
print arg
t = threading.Timer(2, hello, ["bb"])
t.start()
while 1:
pass
You're seeing "b" because you're not giving it an array, so it treats "bb" an an iterable; it's essentially as if you gave it ["b", "b"].
kwargs is for keyword arguments, eg:
t = threading.Timer(2, hello, ["bb"], {arg: 1})
See http://docs.python.org/release/1.5.1p1/tut/keywordArgs.html for information about keyword arguments.

The third argument to Timer is a sequence. Since you pass "bb" as that sequence, hello gets the elements of that sequence ("b" and "b") as separate arguments (arg and kargs). Put "bb" in a list and hello will get the string as the first argument.
t = threading.Timer(2, hello, ["bb"])
As for hello's parameters, you probably mean:
def hello(*args, **kwargs):
The meaning of **kwargs is covered in the queston "What does *args and **kwargs mean?"

Related

Is it possible to pass a dictionary in a wrapper in Python?

I have a function that takes some arguments and uses some variables (but not all) in my dictionary:
def my_fun(arg1, arg2, arg3, **my_dict):
does something...
return output
I need to create a wrapper for this function that only takes 1 argument because I am using the multiprocessing pool package (which only allows 1 argument):
def wrapper(arg):
output = my_fun(arg)
Is it possible to pass arg1, arg2, arg3, **my_dict through the wrapper somehow using arg?
When I try:
def wrapper(**arg):
output = my_fun(arg)
I get the error TypeError: wrapper() takes 3 positional arguments but 4 were given. Thanks in advance!
dic = {"a":1,"b":2}
def my_fun(arg1, arg2, arg3, **dic):
output = arg1, arg2, arg3, dic
return output
def wrapper(arg):
return my_fun(arg[0],arg[1], arg[2], **dic)
x = wrapper([1,2,3, dic])
print(x)
output:
(1, 2, 3, {'a': 1, 'b': 2})
You can't put **dict in your wrapper because ** is part of the function signature syntax, and doesn't have a meaning elsewhere.
You want my_fun to accept 3 mandatory positional arguments followed by zero or more keyword arguments and you want these in a wrapper that you can pass as a single argument. One way to do this is to pass a dict to your function
kwargs=dict(arg1=1, arg2=2, arg3=3, arg4="four", arg5="five")
output = my_fun(**kwargs)
Then inside my_fun do your own validation for the presence of the required arguments arg1, arg2, arg3.
Though I agree with Klaus D. that you may be trying to solve a non-problem here.

Default Initialization of Starred Variables within the Definition of a Function

It is well-known that in order to set a default value to a variable within a function in Python, the following syntax is used:
def func(x = 0):
if x == 0:
print("x is equal to 0")
else:
print("x is not equal to 0")
So if the function is called as such:
>>> func()
It results in
'x is equal to 0'
But when a similar technique is used for starred variables, for example,
def func(*x = (0, 0)):
it results in a syntax error. I've tried switching up the syntax by also doing (*x = 0, 0) but the same error is encountered. Is it possible to initialize a starred variable to a default value?
star variables are non standard variables that are meant to allow functions with arbitrary length
*variables is a tuple with all positional arguments (This is usually named args)
**variables is a dictionary with all named arguments (This is usually named kwargs )
They would always be there, just empty if none is provided. You could test if a value is in the dictionary or tuple depending on what type of argument and initialize it.
def arg_test(*args,**kwargs):
if not args:
print "* not args provided set default here"
print args
else:
print "* Positional Args provided"
print args
if not kwargs:
print "* not kwargs provided set default here"
print kwargs
else:
print "* Named arguments provided"
print kwargs
#no args, no kwargs
print "____ calling with no arguments ___"
arg_test()
#args, no kwargs
print "____ calling with positional arguments ___"
arg_test("a", "b", "c")
#no args, but kwargs
print "____ calling with named arguments ___"
arg_test(a = 1, b = 2, c = 3)
The starred variable has a value of an empty tuple () by default. While it's not possible to change that default value due to how starred parameters work (tl;dr: Python assigns un-starred parameters, if any are available and collects the rest inside a tuple; you can read more about them for example in the relevant PEP 3132: https://www.python.org/dev/peps/pep-3132/) you could implement a check at the beginning of the function to find out if x is an empty tuple and then change it accordingly. Your code would look something like this:
def func(*x):
if x == (): # Check if x is an empty tuple
x = (0, 0)
if x == 0:
print("x is equal to 0")
else:
print("x is not equal to 0")

How to return a single value instead of a tuple?

I realise that in the below functions f returns a tuple, and g returns a list.
def f():
return 1,2
def g():
return [1,2]
a,b=f()
c,d=g()
I have written a function which can handle any number of arguments.
def fun(*args):
return args
These arguments are entered like the f function above because they are the return value from a previous function.
output = fun(other_func())
When more that one value is return from fun the individual values can be retrieved by stating something like this...
output1, output2 = fun(other_func())
However, when one argument is used the output is something like below...
output = fun(other_func())
(1,)
Is there a way when there is only one value to have it return a single element instead of a tuple but still have the functionality of being able to return more than one value?
If you know the function is always going to return a one-element tuple, you can use a one-element tuple assignment:
output, = fun(other_func())
or simply index:
output = fun(other_func())[0]
But in this case, a simple Don't do that, don't return a tuple might also apply:
output = other_func()
As long as *args is a tuple, returning args will therefore return a tuple, even if there is only one parameter.
You should probably do something like:
def fun(*args):
if len(args) == 1:
args, = args
return args
This might be what you are looking for. With this method you must have at least one argument, but you will catch the other arguments in other if you have more.
def funct(*args):
return args
# end funct
if __name__ == '__main__':
foo, *other = funct(1, 2, 3, 4)
print(foo)

Beazley 4e P.E.R: square(x) but he passes **kwargs within the wrapper?

This example is taken from Beazley, Python Essential Reference 4e,
pg:101.
How is he doing:
func(*args, **kwargs)
where 'func' is the square-function which takes 1 argument. Earlier in
the chapter he sqawks about how the position and number of arguments
must match in a call/definition or a TypeError would be raised.
Also,
#trace
def square(x):
...
square = trace(square)
trace returns 'callf' so this is equivalent to writing: square = callf
which is fine because since square refers to a new-function-object, you can
call it with *args, **kwargs. But, then in callf he does func(*args...
Given that we just made 'square' refer to some other object, how is
the original square accessible inside? What mechanism is coming into
play?
#trace
def square(x):
return x*x
enable_tracing = True
if enable_tracing:
debug_log = open("debug.log","w")
def trace(func):
if enable_tracing:
def callf(*args,**kwargs):
debug_log.write("Calling %s: %s, %s\n" %
(func.__name__, args, kwargs))
r = func(*args,**kwargs) #????????
debug_log.write("%s returned %s\n" % (func.__name, r))
return r
return callf
else:
return func
The *-prefix means, "Use this sequence of values as the positional parameters to the function." The **-prefix means, "Use this dictionary as the named parameters to the function." If the sequence is empty, then no positional parameters are passed. If the dictionary is empty, then no named parameters are passed.
When you define a function with those prefixes, then the unaccounted for positional parameters go into the *-prefixed argument, and the unaccounted for named parameters go into the **-prefixed argument. So if you define a function like this:
def wrapper(*args, **kwargs):
then the function can be invoked with any arguments whatsoever. If that function then calls another function with those arguments, then it will be called however the wrapper was called.
Note that you can call a function with (*args, **kwargs) even if wasn't defined that way:
>>> def square(x):
... return x*x
...
>>> args = (10,)
>>> kwargs = {}
>>> square(*args, **kwargs)
100
Because kwargs is empty, there are no named parameters passed to the function. It gets only the one positional arguments in args.

Iterate over *args?

I have a script I'm working on where I need to accept multiple arguments and then iterate over them to perform actions. I started down the path of defining a function and using *args. So far I have something like below:
def userInput(ItemA, ItemB, *args):
THIS = ItemA
THAT = ItemB
MORE = *args
What I'm trying to do is get the arguments from *args into a list that I can iterate over. I've looked at other questions on StackOverflow as well as on Google but I can't seem to find an answer to what I want to do. Thanks in advance for the help.
To get your precise syntax:
def userInput(ItemA, ItemB, *args):
THIS = ItemA
THAT = ItemB
MORE = args
print THIS,THAT,MORE
userInput('this','that','more1','more2','more3')
You remove the * in front of args in the assignment to MORE. Then MORE becomes a tuple with the variable length contents of args in the signature of userInput
Output:
this that ('more1', 'more2', 'more3')
As others have stated, it is more usual to treat args as an iterable:
def userInput(ItemA, ItemB, *args):
lst=[]
lst.append(ItemA)
lst.append(ItemB)
for arg in args:
lst.append(arg)
print ' '.join(lst)
userInput('this','that','more1','more2','more3')
Output:
this that more1 more2 more3
>>> def foo(x, *args):
... print "x:", x
... for arg in args: # iterating! notice args is not proceeded by an asterisk.
... print arg
...
>>> foo(1, 2, 3, 4, 5)
x: 1
2
3
4
5
edit: See also How to use *args and **kwargs in Python (As referenced by Jeremy D and subhacom).
If you do that :
def test_with_args(farg, *args):
print "formal arg:", farg
for arg in args:
print "other args:", arg
Other information: http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
MORE = args
Or, directly:
for arg in args:
print "An argument:", arg
If your question is "how do I iterate over args", then the answer is "the same way you iterate over anything": for arg in args: print arg.
Just iterate over args:
def userInput(ItemA, ItemB, *args):
THIS = ItemA
THAT = ItemB
for arg in args:
print arg

Categories