When I put a delay before a loop that has delay inside a function, the function seem to not delay and loop when called.
from time import *
from random import *
def _print(s):
global e_times
print(s)
return 10
def doloop(l_delay, s_delay):
sleep(s_delay)
while True:
sleep(l_delay)
doloop(_print('Hello, world!'), 20)
My expectation that the output must delay for 20 seconds then and for each 10 seconds it must print the 'Hello, world!' string once. But when executed, it doesn't both delay and loop. What should I do?
doloop(_print('Hello, world!'), 20)
This will do the following:
evaluate _print('Hello world!') -> get 10
call doLoop like this: doLoop(10, 20)
Functions arguments are evaluated first before being passed down to functions.
So you will obviously not get a loop that calls the function multiple times.
What you need to do is pass the function itself to the doLoop method. And use it's return value.
def doloop(call_func, s_delay):
sleep(s_delay)
while True:
l_delay = call_func()
sleep(l_delay)
And then call it with:
doloop(lambda: _print('Hello, world!'), 20)
The lambda here, turns the function call into a closure (the argument is bound to the method)
It really doesn't make sense to me about your functions after reading your expectation about the program you want to build... I would simply use the following code:
from time import sleep
def _print(n, s): # n = sleep for seconds, s = string to print
while True: # infinite loop
print(s) # print the string
sleep(n) # sleep for number of seconds you specify
sleep(20) # initial sleep of 20 seconds
_print("Hello, World!", 10) # run the custom print function which sleeps for n seconds and prints s string
Hope you have got what you want.
from time import *
from random import *
def _print(s):
global e_times
print(s)
return 10
def doloop(call_func, s_delay):
sleep(s_delay)
while True:
l_delay = call_func()
sleep(l_delay)
doloop(lambda: _print('Hello, world!'), 20)
you have to use lambda function sometimes. lamda functions like variables passed to the function.
Related
The script below should set up scheduling at two specified times while passing individual parameters to each run. In this case the output should be 1 and 2, however the output is 2 and 2, somehow passing only the last variable to the parameters.
import schedule, threading, time
def run_script(n):
#Check this output
print(n)
def run_threaded(job_func):
job_thread = threading.Thread(target=job_func)
job_thread.start()
times = ["13:56", "13:56"]
for n,row in enumerate(times, 1):
schedule.every().day.at(row).do(run_threaded, lambda: run_script(n))
while True:
schedule.run_pending()
time.sleep(1)
If you run the script without the loop manually like this:
schedule.every().day.at("18:56").do(run_threaded, lambda: run_script(1))
schedule.every().day.at("18:56").do(run_threaded, lambda: run_script(2))
This works fine! However when generated by the loop the result is not the same.
Does anyone have any idea why and how to solve this?
So I’m trying to have a strobe like effect on a game I’m building and the way I currently have it it’s destroying my frame rate because the sleep function is also applying to the draw function. Can someone explain why this happens? And the logic that I’m failing to understand. Why can’t I just have the return happen every .5 seconds without it affecting the .1 sleep I have in my hue function?
Here’s a crude demonstration of what the code kind of does.
from random import randint
import time
def rand_intr():
r = randint(1,256)
time.sleep(.5)
return r
def rand_intg():
g = randint(1,256)
time.sleep(.5)
return g
def rand_intb():
b = randint(1,256)
time.sleep(.5)
return b
def hue():
r = rand_intr()
g = rand_intg()
b = rand_intb()
print(r, g, b)
print('test')
time.sleep(.01)
while True:
hue()
The sleep function blocks the main thread. This means rand_intg does not run until rand_intr "wakes up" from its sleep.
Similarly, rand_intb has to wait for rand_intg, and hue has to wait for all the previous 3 functions. This means the total time hue has to wait before it can do any work is at least the amount of time needed to complete rand_intr, rand_intg, and rand_intb.
We can understand what is happening if we modify your example slightly and look at the output.
from random import randint
import time
def log_entry_exit(f):
def wrapped():
print("Entered {}".format(f.__name__))
result = f()
print("Leaving {}".format(f.__name__))
return result
return wrapped
#log_entry_exit
def rand_intr():
r = randint(1,256)
time.sleep(.5)
return r
#log_entry_exit
def rand_intg():
g = randint(1,256)
time.sleep(.5)
return g
#log_entry_exit
def rand_intb():
b = randint(1,256)
time.sleep(.5)
return b
def hue():
r = rand_intr()
g = rand_intg()
b = rand_intb()
print(r, g, b)
print('test')
time.sleep(.01)
while True:
hue()
Here I just modified your functions to print a message when we enter and exit each function.
The output is
Entered rand_intr
Leaving rand_intr
Entered rand_intg
Leaving rand_intg
Entered rand_intb
Leaving rand_intb
172 206 115
test
Entered rand_intr
Leaving rand_intr
Entered rand_intg
Leaving rand_intg
Entered rand_intb
Leaving rand_intb
240 33 135
test
...
Here, the effect of each sleep on hue can be seen clearly. You don't get to print the rgb values or "test" until the previous functions have completed.
What you can do is to call your hue function periodically using a timer callback, and then modify the rgb values according to some pattern. See this stackoverflow question on
executing periodic actions for an example on how to periodically execute a function using a basic time-based mechanism.
Edit
Based on your comment to #jasonharper
If you call hue every 60 seconds, it does not make sense if your calls to the functions that generate the random rgb values occur at a faster rate because any changes in the intervening time will not be seen in hue.
What you can do is call hue every 60 seconds, then generate your rgb values to have whatever pattern in there.
Modifying the answer by #kev in the post I linked to above,
import time, threading
def update():
# Do whatever you want here.
# This function will be called again in 60 seconds.
# ...
hue()
# Whatever other things you want to do
# ...
threading.Timer(60.0, update).start()
def hue():
r = rand_intr()
g = rand_intg()
b = rand_intb()
print(r, g, b)
# Don't call sleep.
if __name__ == "__main__":
update()
Now you should only call update once, possibly in some startup part of your code and remove all the calls to sleep in your functions.
I want a timer, but I want it to just affect one function, so it can't just be
sleep().
For example:
def printSomething():
print("Something")
def functionWithTheTimer():
for i in range(0, 5):
#wait for 1 second
print("Timer ran out")
Say the first function is called when a button is clicked, and the second function should print something out every second, both should act independently.
If I used sleep(), I couldn't execute the first function within that one second, and that's a problem for me. How do I fix this?
For your timer function, you may want to do something like this:
def functionWithTheTimer():
for i in reversed(range(1, 6)):
print(i)
time.sleep(1)
print("finished")
This will print the range backwards (like a countdown), one number every second.
EDIT: To run a function during that time, you can just duplicate and shorten the wait time. Example:
def functionWithTheTimer():
for i in reversed(range(1, 6)):
print(i)
time.sleep(0.5)
YourFunctionHere()
time.sleep(0.5)
print("finished")
You can play with the timings a little so you can get your appropriate output.
You can use the datetime library like this:
from datetime import datetime
def functionwithtimer():
start_time = datetime.now()
# code stuff you have here
print("This function took: ", datetime.now() - start_time)
need help for this code
import timeit
mysetup=""
mycode='''
def gener():
...my code here...
return x
'''
# timeit statement
print (timeit.timeit(setup = mysetup,
stmt = mycode,
number = 1000000))
print("done")
As result I got 0.0008606994517737132
As I read this unit is in "seconds"
So my funtion executed 1 million time in 0.8 ms ?
I think this is not real, too fast.
I also tried basic option
start = time.time()
my code here
end = time.time()
print(end - start)
and got 0.23901081085205078 for one time execution it seems a little slow...
So what I'm I doing wrong ?
Thanks
The way you have defined this in mycode for the timeit method, all that is going to happen is the function gener will be defined, not run. You need to run the function in your code block in order to report time taken for execution.
As for what length of time is reasonable (too fast/too slow) it very much depends on what your code is doing. But I suspect you have executed the function in method 2 and only defined it in method 1, hence the discrepancy.
Edit: example code
To illustrate the difference, in the example below the block code1 just defines a function, it does not execute it. The block code2 defines and executes the function.
import timeit
code1 = '''
def gener():
time.sleep(0.01)
'''
code2 = '''
def gener():
time.sleep(0.01)
gener()
'''
We should expect running time.sleep(0.01) 100 times to take approximately 1 second. Running timeit for code1 returns ~ 10^-5 seconds, because the function gener is not actually being called:
timeit.timeit(stmt=code1, number=100)
Running timeit for code2 returns the expected result of ~1 second:
timeit.timeit(stmt=code2, number=100)
Further to this, the point of the setup argument is to do setup (the parts of the code which are not meant to be timed). If you want timeit to capture the execution time of gener, you should use this:
import timeit
setup = '''
def gener():
time.sleep(0.01)
'''
stmt = "gener()"
timeit.timeit(setup=setup, stmt=stmt, number=100)
This returns the time taken to run gener 100 times, not including the time taken to define it.
Here is a general way to measure time of code snippets.
import time
class timer(object):
"""
A simple timer used to time blocks of code. Usage as follows:
with timer("optional_name"):
some code ...
some more code
"""
def __init__(self, name=None):
self.name = name
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
self.end = time.time()
self.interval = self.end - self.start
if self.name:
print("{} - Elapsed time: {:.4f}s".format(self.name, self.interval))
else:
print("Elapsed time: {:.4f}s".format(self.interval))
gist available here: https://gist.github.com/Jakobovski/191b9e95ac964b61e8abc7436111d1f9
If you want to time a function timeit can be used like so:
# defining some function you want to time
def test(n):
s = 0
for i in range(n):
s += i
return s
# defining a function which runs the function to be timed with desired input arguments
timed_func = lambda : test(1000)
# the above is done so that we have a function which takes no input arguments
N = 10000 # number of repeats
time_per_run = timeit.timeit(stmt=timed_func, number=N)/N
For your case you can do:
# defining some function you want to time
def gener():
...my code here...
return x
N = 1000000 # number of repeats
time_per_run = timeit.timeit(stmt=gener, number=N)/N
Any importing of libraries can be done globally before calling the timeit function and timeit will use the globally imported libraries
e.g.
import numpy as np
# defining some function you want to time
def gener():
...my code here...
x = np.sqrt(y)
return x
N = 1000000 # number of repeats
time_per_run = timeit.timeit(stmt=gener, number=N)/N
Working code
# importing the required module
import timeit
# code snippet to be executed only once
mysetup = '''
from collections import OrderedDict
def gener():
some lines of code here
return x'''
# code snippet whose execution time is to be measured
mycode="gener()"
# timeit statement
nb=10
print("The code run {} time in: ".format(nb ))
print("{} secondes".format(timeit.timeit(setup = mysetup,
stmt = mycode,
number = nb)))
print("done")
execution time was almost the same with the one got below
start = time.time()
my code here
end = time.time()
print(end - start)
0.23 sec with timeit and with the basic measurement code above 0.24 ,they both fluctuate...
So thanks, question resolved
I am trying to make a timer to execute a block of code every second let's say, using tkinter in python. But instead of executing the code every second, which is moving a label across a canvas, it seems to buffer and wait until the loop is finished and only then display the moved label. Beneath is the piece of coding where I think the problem is found. I personally think the for-loop in the second function is creating problems, but I don't know how to solve this.
def roll(self):
number=randint(2,12)
print number
if self.a==0:
self.place_player_1(self.start_turn_pos_1,number+self.start_turn_pos_1)
self.start_turn_pos_1+=number
elif self.a==1:
self.place_player_2(self.start_turn_pos_2,number+self.start_turn_pos_2)
self.start_turn_pos_2+=number
return number
def place_player_1(self,start_turn_pos_1,number):
#Define the board
for i in range(self.start_turn_pos_1,number+1,1):
self.c.after(1000,self.move_1(i))
def move_1(self,i):
e1=streets_x[i]
g1=streets_y[i]
self.label_player1.place(x=e1,y=g1)
self.move_1(i) calls the method immediately. To postpone the call:
self.c.after(1000, self.move_1, i) #note: no parentheses
To repeat the call every second, add .after call at the end of self.move_1 method:
def place_player_1(self,start_turn_pos_1,number):
self.c.after(1000, self.move_1, start_turn_pos_1, number) # call in a sec
def move_1(self,i, limit):
e1=streets_x[i]
g1=streets_y[i]
self.label_player1.place(x=e1,y=g1)
if i < limit: # schedule the next call
self.c.after(1000, self.move_1, i + 1, limit)
See setTimeout(), setInterval() analogs in Python using tkinter, or gtk, or twisted.
All function calls happen at the same time:
self.c.after(1000,self.move_1(i))
Because the are called after 1000 milliseconds.
Make the delay larger for each step. For example:
def place_player_1(self,start_turn_pos_1,number):
#Define the board
delay = 1000
for index, i in enumerate(range(self.start_turn_pos_1, number + 1), 1):
self.c.after(delay * index, self.move_1, i)
Now you schedule the function calls for different times.