Postponing functions in python
You want a Timer
object from the threading
module.
from threading import Timer
from time import sleep
def foo():
print "timer went off!"
t = Timer(4, foo)
t.start()
for i in range(11):
print i
sleep(.5)
If you want to repeat, here's a simple solution: instead of using Timer
, just use Thread
but pass it a function that works somewhat like this:
def call_delay(delay, repetitions, func, *args, **kwargs):
for i in range(repetitions):
sleep(delay)
func(*args, *kwargs)
This won't do infinite loops because that could result in a thread that won't die and other unpleasant behavior if not done right. A more sophisticated approach might use an Event
-based approach, like this one.
Postpone code for later execution in python (like setTimeout in javascript)
In practice, a Timer is probably the simplest way to do what you want.
This code will do the following:
- After 1 second, it prints "arg1 arg2"
- After 2 seconds, it prints "OWLS OWLS OWLS"
===
from threading import Timer
def twoArgs(arg1,arg2):
print arg1
print arg2
print ""
def nArgs(*args):
for each in args:
print each
#arguments:
#how long to wait (in seconds),
#what function to call,
#what gets passed in
r = Timer(1.0, twoArgs, ("arg1","arg2"))
s = Timer(2.0, nArgs, ("OWLS","OWLS","OWLS"))
r.start()
s.start()
===
The above code will most likely solve your problem.
But! There is alternative way, that doesn't use multithreading. It works much more like Javascript, which is single-threaded.
For this single-thread version, all you need to do is store the function and its arguments in an object, along with the time at which the function should be run.
Once you have the object containing the function call and the timeout, just periodically check if the function is ready to execute.
The right way to do this is by making a priority queue to store all of the functions we want to run in the future, as shown in the code below.
Just like in Javascript, this approach makes no guarantee that the function will be run exactly on time. A function that takes a very long time to run will delay the functions after it. But it does guarantee that a function will be run no sooner than its timeout.
This code will do the following:
- After 1 second, it prints "20"
- After 2 seconds, it prints "132"
- After 3 seconds, it quits.
===
from datetime import datetime, timedelta
import heapq
# just holds a function, its arguments, and when we want it to execute.
class TimeoutFunction:
def __init__(self, function, timeout, *args):
self.function = function
self.args = args
self.startTime = datetime.now() + timedelta(0,0,0,timeout)
def execute(self):
self.function(*self.args)
# A "todo" list for all the TimeoutFunctions we want to execute in the future
# They are sorted in the order they should be executed, thanks to heapq
class TodoList:
def __init__(self):
self.todo = []
def addToList(self, tFunction):
heapq.heappush(self.todo, (tFunction.startTime, tFunction))
def executeReadyFunctions(self):
if len(self.todo) > 0:
tFunction = heapq.heappop(self.todo)[1]
while tFunction and datetime.now() > tFunction.startTime:
#execute all the functions that are ready
tFunction.execute()
if len(self.todo) > 0:
tFunction = heapq.heappop(self.todo)[1]
else:
tFunction = None
if tFunction:
#this one's not ready yet, push it back on
heapq.heappush(self.todo, (tFunction.startTime, tFunction))
def singleArgFunction(x):
print str(x)
def multiArgFunction(x, y):
#Demonstration of passing multiple-argument functions
print str(x*y)
# Make some TimeoutFunction objects
# timeout is in milliseconds
a = TimeoutFunction(singleArgFunction, 1000, 20)
b = TimeoutFunction(multiArgFunction, 2000, *(11,12))
c = TimeoutFunction(quit, 3000, None)
todoList = TodoList()
todoList.addToList(a)
todoList.addToList(b)
todoList.addToList(c)
while True:
todoList.executeReadyFunctions()
===
In practice, you would likely have more going on in that while loop than just checking if your timeout functions are ready to go. You might be polling for user input, controlling some hardware, reading data, etc.
How can I call a function with delay in python?
Patrick: See this thread - How to create a timer using tkinter?
You can use Threading.Timer to do this. It has a cancel
method that you can use to cancel it before it runs.
Delay timer to use a function in python
Here is your code, cleaned up to remove Java-like getter/setter which are not necessary in Python:
import time
class MyClass():
def __init__(self):
self.last_use = 0
def Foo(self):
elapsed = time.time() - self.last_use
if elapsed < 5:
print("Wait 5 seconds")
return
self.last_use = time.time()
print("Let's Foo!")
mc = MyClass()
mc.Foo()
mc.Foo()
mc.Foo()
mc.Foo()
print('wait a bit now...')
time.sleep(5)
mc.Foo()
The main syntax error you had was omitting the ':' on your if statement. Logic-wise, your > 5
should really be < 5
.
This prints:
Let's Foo!
Wait 5 seconds
Wait 5 seconds
Wait 5 seconds
wait a bit now...
Let's Foo!
EDIT:
Here is the advanced version, where a wait_at_least
decorator takes
care of the overhead logic of checking the elapsed time between calls, and your
various FooX()
methods just do what FooX()
methods do:
def wait_at_least(min_wait_time):
"a decorator to check if a minimum time has elapsed between calls"
def _inner(fn):
# a wrapper to define the last_call value to be preserved
# across function calls
last_call = [0]
def _inner2(*args, **kwargs):
# the function that will actually be called, checking the
# elapsed time and only calling the function if enough time
# has passed
elapsed = time.time() - last_call[0]
if elapsed < min_wait_time:
msg = "must wait {:.2f} seconds before calling {} again".format(min_wait_time - elapsed, fn.__name__)
print(msg)
# consider doing 'raise NotYetException(msg, min_wait_time, elapsed)`
# instead of just returning
return
last_call[0] = time.time()
return fn(*args, **kwargs)
return _inner2
return _inner
class MyClass():
def __init__(self):
pass
@wait_at_least(5)
def Foo(self):
print("Let's Foo!")
@wait_at_least(3)
def Foo2(self):
print("We can Foo2!")
mc = MyClass()
mc.Foo()
mc.Foo2()
mc.Foo()
mc.Foo2()
time.sleep(1.5)
mc.Foo()
mc.Foo2()
print('wait a bit now...')
time.sleep(3)
mc.Foo()
mc.Foo2()
print('wait a little bit more...')
time.sleep(2)
mc.Foo()
mc.Foo2()
I added Foo2 to show that the two methods keep separate timers, and can take different minimum wait times between calls.
Prints:
Let's Foo!
We can Foo2!
must wait 5.00 seconds before calling Foo again
must wait 3.00 seconds before calling Foo2 again
must wait 3.50 seconds before calling Foo again
must wait 1.50 seconds before calling Foo2 again
wait a bit now...
must wait 0.50 seconds before calling Foo again
We can Foo2!
wait a little bit more...
Let's Foo!
must wait 1.00 seconds before calling Foo2 again
How to postpone a method to be done after each save() in Django?
Use a task scheduler like Celery with a task queue and delay the processing of the favicon.
I have done a python decorator for this http://mpcabd.igeex.biz/python-celery-asynchronous-task-decorator/ which can help you understanding how this works and if you use this decorator you can make your code clear and won't repeat it IMHO.
How to delay a part of my program without affecting the rest?
You need to use a different thread for your score calculation. Just start a new thread for counting down your score.
import threading
import time
def scoreCounter():
while shipy > 400:
time.sleep(0.1)
global score
score-=1
t1 = threading.Thread(target=scoreCounter)
Then just call t1.start()
at some point in the code if shipy > 400
.
Python equivalent of golang's defer statement
To emulate defer fmt.Println(*a, i)
example, you could use contextlib.ExitStack
:
#!/usr/bin/env python3
from contextlib import ExitStack
from functools import partial
print("counting")
with ExitStack() as stack:
for i in range(10):
a = i
stack.callback(partial(print, a, i))
x = 42
a = x
print("done")
Output
counting
done
9 9
8 8
7 7
6 6
5 5
4 4
3 3
2 2
1 1
0 0
It is easy to emulate the mutex case:
def some_function(lock=Lock()):
with lock:
# whatever
Related Topics
Why Doesn't a Python Dict.Update() Return the Object
Repeat Rows in a Pandas Dataframe Based on Column Value
Convert a List of Characters into a String
How to Override the [] Operator in Python
Can Python Pickle Lambda Functions
Python Subprocess.Call a Bash Alias
Why Are There No ++ and -- Operators in Python
How to Clone a Django Model Instance Object and Save It to the Database
Cost of Exception Handlers in Python
Python: Can Executable Zip Files Include Data Files
Calculate Average of Every X Rows in a Table and Create New Table
Pylab.Ion() in Python 2, Matplotlib 1.1.1 and Updating of the Plot While the Program Runs
How to Print Bold Text in Python
How Does Condensed Distance Matrix Work? (Pdist)
Split a Generator into Chunks Without Pre-Walking It
How to Use the 'JSON' Module to Read in One JSON Object at a Time