Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I want to create a thread which runs a list of functions which are passed to it, the list can be updated real time so a function in the list could be switched out.
What is the correct way to do this? How would I create a variable list of functions in Python?
Here is example:
Code
class a:
def f1(self, i):
print(f'function 1 executed, index={i}')
def f2(i):
print(f'function 2 executed, index={i}')
def f3(i):
print(f'function 3 executed, index={i}')
object_of_a = a()
function_list = [object_of_a.f1, f2]
for arg, fn in enumerate(function_list):
fn(arg)
function_list[1] = f3
for arg, fn in enumerate(function_list):
fn(arg)
Output
function 1 executed, index=0
function 2 executed, index=1
function 1 executed, index=0
function 3 executed, index=1
Here is an example with a list of arguments:
Code
def f1(i):
print(f'function 1 executed, arg={i}')
def f2(i):
print(f'function 2 executed, arg={i}')
def f3(i):
print(f'function 3 executed, arg={i}')
function_list = [f1, f2]
argument_list = ['arg1', 'arg2']
for arg, fn in zip(argument_list, function_list):
fn(arg)
function_list[1] = f3
for arg, fn in zip(argument_list, function_list):
fn(arg)
Output
function 1 executed, arg=arg1
function 2 executed, arg=arg2
function 1 executed, arg=arg1
function 3 executed, arg=arg2
Functions can be stored in lists just like variables and data structures can be. When adding them to a list, be sure to only use the name of the function and to exclude the () so that it adds the function itself, rather than the output of the function.
There are a couple ways you could make it so that the list can be updated in real time. As long as the thread is able to look up externally accessible data, it will work. For two examples, the thread could access class data or data stored in a file.
Here's some sample code for a class data example:
import threading
import time
class Obj:
def __init__(self):
self.functions = []
def call_functions(self):
for function in self.functions:
function()
time.sleep(5)
def add_function(self, function):
self.functions.append(function)
def a():
print("a")
def b():
print("b")
def c():
print("c")
if __name__ == "__main__":
obj = Obj()
obj.add_function(a)
obj.add_function(b)
thread = threading.Thread(target=obj.call_functions)
thread.start()
obj.add_function(c)
Related
I'm trying to use returned data from one function into multiple other functions. But I don't want the first function to run each time; which is happening in my case.
#Function lab
def func_a():
print('running function a')
data = 'test'
return data
def func_b():
print(func_a())
def func_c():
print(func_a())
def func_d():
print(func_a())
if __name__ == '__main__':
func_a()
func_b()
func_c()
func_d()
Each time that whole function_a runs. But I just want the returned data from "func_a" in other functions.
IIUC, you could alleviate this with a simple class.
I hold the state of the class which runs func_a in a variable called output. I can then reference this output variable once the class has finished running as much as I like in all other functions without having to re-run func_a.
Hope this helps!
class FunctionA:
def __init__(self):
self.output = None
def run_function(self):
print('running function a')
data = 'test'
self.output = data
def func_b():
print(func_a.output)
def func_c():
print(func_a.output)
def func_d():
print(func_a.output)
if __name__ == '__main__':
func_a = FunctionA()
func_a.run_function()
func_b()
func_c()
func_d()
>>> running function a
>>> test
>>> test
>>> test
Your func_a does two things. To make this clear, let's call it, print_and_return_data.
There are several ways to to break apart the two things print_and_return_data does. One way is to split up the two behaviors into smaller sub-methods:
def print_and_return_data():
print('running function a') # keeping the old print behavior
data = 'test'
return data
into:
def print_run():
print('running function a') # keeping the old print behavior
def return_data():
return 'test'
def print_and_return_data():
print_run()
return return_data()
So that other functions only use what they need:
def func_b():
print(return_data())
Another way is to change print_and_return_data to behave differently the first time it's called from the following times it's called (I don't recommend this because functions changing based on how many times it's been called can be confusing):
context = {'has_printed_before': False}
def print_and_return_data():
if not context['has_printed_before']:
print('running function a')
context['has_printed_before'] = True
data = 'test'
return data
def func_b():
print(print_and_return_data())
if __name__ == '__main__':
func_a() # prints
func_b() # won't print
One way to avoid "functions behaving differently when they're called" is to pass the variation (the "context") in as an argument:
def return_data(also_print=False):
if also_print:
print('running function a')
data = 'test'
return data
def func_b():
print(return_data())
if __name__ == '__main__':
func_a(also_print=True) # prints
func_b() # won't print
I have a question about adding delay after calling various functions.
Let's say I've function like:
def my_func1():
print("Function 1")
def my_func2():
print("Function 2")
def my_func3():
print("Function 3")
Currently I've added delay between invoking them like below:
delay = 1
my_func1()
time.sleep(delay)
my_func2()
time.sleep(delay)
my_func3()
time.sleep(delay)
As you can see I needed a few times time.sleep, which I would like to avoid.
Using decorator is also not an option, since it might be that I would like to avoid delay when calling one of this function not in a group.
Do you have any tip how to beautify this?
You can define something like this:
def delay_it(delay, fn, *args, **kwargs):
return_value = fn(*args, **kwargs)
time.sleep(delay)
then
a = delay_it(1, my_func1, "arg1", arg2="arg2")
b = delay_it(1, my_func2, "arg3")
...
I've tested this based on "How to Make Decorators Optionally Turn On Or Off" (How to Make Decorators Optionally Turn On Or Off)
from time import sleep
def funcdelay(func):
def inner():
func()
print('inner')
sleep(1)
inner.nodelay = func
return inner
#funcdelay
def my_func1():
print("Function 1")
#funcdelay
def my_func2():
print("Function 2")
#funcdelay
def my_func3():
print("Function 3")
my_func1()
my_func2()
my_func3()
my_func1.nodelay()
my_func2.nodelay()
my_func3.nodelay()
Output:
Function 1
inner
Function 2
inner
Function 3
inner
Function 1
Function 2
Function 3
You can see that it can bypass the delay.
Not sure if I know what you mean but you could try:
functions = [my_func1, my_func2, my_func3]
for func in functions:
func()
time.sleep(1)
It's not a good way to handle delay in a function; because each function should do only one thing.
Dont't do this:
def my_func(delay):
# do stuff
if delay>0:
time.sleep(delay)
Try to make a delay handler function and put suitable delay after each function you pass to it.
Try this:
def delay_handler(functions_list,inputs_list,delay_list):
for function,cur_input,delay in zip(functions_list,inputs_list,delay_list):
function(*cur_input)
time.sleep(delay)
Tip 1: Zip will iterate throw each list (any iterable) simultaneously; first elements in inputs_list and delay_list are for first function in function_list and etc.
Tip 2: The '*' behind a list will unpack it.
I have the following code and I have a hard time understanding why it prints the statements in the order it does.
def main():
print('1')
registry=[]
def register(func):
print('2')
registry.append(func)
return func
#register
def f1():
print('3')
print('4')
f1()
main()
This code prints:
1
2
4
3
But I'm wondering why it doesn't print:
1
2
3
4
when the #register is called I understand it that register(f1) is called, it prints 2 and then f1 is returned. To me it seems like 3 should be printed next since f1 is returned. But instead f1 is not called until the very end f1() statement. Doesn't return func run the function it returns?
Consider the equivalent code that doesn't use decorator syntax. Also, we make registry a pre-defined global so that the code actually runs.
registry = []
def main():
print('1')
#registry=[]
def register(func):
print('2')
registry.append(func)
return func
def f1():
print('3')
f1 = register(f1)
print('4')
f1()
main()
The first function that gets called is register, so the first value output is 2. Next, print('4') outputs 4. Third, f1 is called and outputs 3. Finally, main is called and outputs 1.
register never calls f1; it simply adds it to the list registry and returns it.
I have defined TaskTimer Class below and that I would like to execute multiple functions when the event is triggered which may or may not have arguements. I would like to come up with a generic way of doing this. My functions are not being executed and I do not undestand why. Are my arguements in t.start() incorrect?
import System
from System.Timers import (Timer, ElapsedEventArgs)
class TaskTimer(object):
def __init__ (self):
self.timer = Timer ()
self.timer.Enabled = False
self.handlers =[]
def On_Timed_Event (self,source, event):
print 'Event fired', event.SignalTime
for handler in self.handlers:
handler(*self.my_args,**self.kwargs)
def start(self,interval, repeat, *args, **kwargs):
self.repeat = repeat
self.run = True #True if timer is running
self.timer.Interval= interval
self.timer.Enabled = True
self.my_args= args
self.kwargs = kwargs
for x in self.my_args:
self.handlers.append(x)
self.timer.Elapsed += self.On_Timed_Event
def func1(a,b):
print 'function 1. this function does task1'
print '1...1...1...'
return None
def func2(d):
print 'Function 2. This function does something'
print '2...2...2...'
return None
def func3(a,b,c):
print 'function 3. This function does something else'
return None
def main():
t= TaskTimer()
D= {'fun2':'func2', 'arg2':'3'}
t.start(5000,False,func1, func2, func3, a= 1, b=3, c=4, d=D)
if __name__ == '__main__':
main()
I am experimenting so I edited the def_Timed_Event function and func1, func2 and func3 as shown below. I also added print statement to the functions as suggested by #Ewan. Does Python automatically substitute function variables from **self.kwargs?
def On_Timed_Event (self,source, event):
print '\nEvent fired', event.SignalTime
for handler in self.handlers:
print 'length of self.handlers', len(self.handlers)
print 'args', self.my_args
print 'kwargs', self.kwargs
print 'handler', handler
handler(**self.kwargs)
self.handler[handler](**self.kwargs)
def func1(a,b):
print 'function 1. this function does task1'
print 'func1', a,b
print '1...1...1...'
return None
def func2(d):
print 'Function 2. This function does something'
print 'func2', d
print '2...2...2...'
return None
def func3(a,b,c):
print 'function 3. This function does something else'
print 'func3', a,b,c
return None
The code runs inside IronPyhton console.
![IronPython_console][2]
[2]: http://i.stack.imgur.com/vYW0S.jpg
First of all I can see you having trouble with this line:
handler(*self.my_args,**self.kwargs)
As you aren't accepting any extra kwargs in func1, func2 or func3 I would expect to see the following if it was reaching them:
In [1]: def func1(a, b):
...: print(a, b)
...:
In [2]: kwg = {'a':1, 'b':3, 'c':4, 'd':{'fun2':'func2', 'arg2':'3'}}
In [3]: func1(**kwg)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-12557b6441ce> in <module>()
----> 1 func1(**kwg)
TypeError: func1() got an unexpected keyword argument 'c'
Personally I'd put some decent logging/debug statements in to find out where your program is getting in your stack.
Is the program completing successfully or are you getting a TraceBack?
What is this designed to do: self.timer.Elapsed += self.On_Timed_Event?
It looks like it's supposed to be adding a time onto your timer.Elapsed value however nothing is returned by self.On_Timed_Event
On_Timed_Event takes 2 parameters (source, event) however you don't seem to be passing them in, this should also cause the program to fail.
Are you seeing Event fired in your stdout or is the program not getting to On_Timed_Event at all? This may show a problem in your System.Timers code.
I am trying to do a progress bar.
Would it be possible to count the number of execution lines on a script and associate each execution line with a function so that it is executed every line or every 5 lines?
My plan is to update a progress bar every time a line is executed.
Is it possible? Can I use decorators to do it?
Yep, you can do that by asking Python to alert you every time it processes a line. Here's an example that prints to stdout after every updatelines times a line is executed:
import sys
class EveryNLines(object):
def __init__(self, updatelines):
self.processed = 0
self.updatelines = updatelines
def __call__(self, frame, event, arg):
if event == 'line':
self.processed += 1
if not self.processed % self.updatelines:
print 'do something'
return self
def testloop():
for i in range(5):
print i
oldtracer = sys.gettrace()
sys.settrace(EveryNLines(3))
testloop()
sys.settrace(oldtracer)
You could certainly turn that into a decorator for convenience.
Could you benefit from an Observer object?
class Observer(object):
def __init__(self):
self._subjects = []
def add_subject(self, subject):
self._subjects.append(subject)
def notify(self, percentage):
for subject in self._subjects:
subject.notify(percentage)
class Subject(object):
def notify(self, percentage):
# in this example, I assume that you have a class
# that understand what does "update_progress_bar(%)" means
# and it is inheriting from `Subject`
self.update_progress_bar(percentage)
s = Subject()
o = Observer()
o.add_subject(s)
# your code
def my_fun():
blah()
blah2()
o.notify(20)
blah3()
o.notify(30)
blah4()
o.notify(100)
So, you create an Observer class whose only purpose is to keep track of the runtime. You can create one or several Subject objects which can be notified by the Observer: in this case they get notified the percentage completion. When each Subject gets notified, they can do whatever they want to, like update a progress bar.