I'm looking for solution of this problem:
I have two functions:
def foo1():
while True:
print("x")
def foo2():
while True:
print("y")
I would like to run them alternately, like:
run foo1()
stop foo1() run foo2()
stop foo2() run foo1()
Functions can't work simultaneously, at the moment only one of them can work.
Edit: Leave it to #StefanPochmann to shoot down my beautiful answer: It doesn't matter for the question as it is posed, but it is certainly worth mentioning that zip works pair-by-pair. So while you can formally pause alter defined below after an odd number of iterations, at this point 'y' will have been printed already.
If you care about this the solution also due to Stefan is
>>> alter = map(next, it.cycle((foo1(), foo2())))
which is actually pretty clever.
Edit ends
You could convert the functions into generators, then zip them.
>>> import itertools as it
>>>
>>> def foo1():
... while True:
... print("x")
... yield None
...
>>> def foo2():
... while True:
... print("y")
... yield None
...
>>> alter = it.chain.from_iterable(zip(foo1(), foo2()))
>>> while True:
... next(alter)
x
y
x
y
...
or:
>>> for a in alter:
... pass
x
y
x
y
...
I personally favour the itertools approach by Paul Panzer. However, if it is an option, I'd strongly suggest moving the "infinite loop" out of these functions and instead putting it in another "driver" function that calls these two in an alternating fashion.
def f1():
print('x')
def f2():
print('y')
def driver():
while True:
f1()
f2()
I get that this won't be possible to implement in every situation, but it does lead to better design in the end if you can.
There's no way to do what you want with the functions you've shown. However, there are some approaches that might come close, to differing degrees, depending on what details you're willing to change in your current code.
One option to get sort-of parallel execution is to use threads. Python doesn't actually allow more than one thread to be running Python code at once, so this isn't really useful in most situations, but it might be good enough for your specific use case. Unfortunately it does very badly with your current code, since one thread will tend to block the other for a long time, so you'll get lots of xs, followed by lots of ys, as they functions only swap the GIL irregularly.
Another option is to use multiprocessing, which does allow parallel execution. It would do a better job of interleaving your two functions, but the exact timing of the swaps between the two processes will still not be exactly consistent, so you won't always get "xyxyxyxy", you might get something more like "xyxxyyxy" (the exact details may depend on your OS, CPU and how busy your machine is at the time you run the code).
Now we get into solutions that require modifications to the functions. An obvious solution is to simply rewrite them into a single function that does both steps:
def foo_combined():
while True:
print('x')
print('y')
Another option is to make the functions into generators, which you can combine yourself using zip:
def foo1_gen():
while True:
yield 'x'
def foo2_gen():
while True
yield 'y'
You could consume the generators like this:
for x, y in zip(foo1_gen(), foo2_gen()):
print(x)
print(y)
Or, if you want a single iterable:
for val in itertools.chain.from_iterable(zip(foo1_gen(), foo2_gen())):
print(val)
From what you say you don't want/need for them really both be running at the same time, but rather to be able to switch execution back and forth among them. What you've describe is what's called co-operative multitasking.
This can be accomplished by simply making each function a coroutine. In Python that can be accomplished by making them generator functions which is done by simply by adding a yield statement to them at the right spot. That way they will each pause execution until next() is called on them again.
The only slightly tricky part is remembering that each generator function will need to be "primed" once it's called the first time (which actually doesn't execute the code in the function). The first call to next() of the value returned by the first call to the function itself will advances its execution to the location of the first yield in it.
Here's what I mean:
def foo1():
while True:
yield
print("x")
def foo2():
while True:
yield
print("y")
# Sample usage.
def process():
f1 = foo1()
next(f1) # Prime generator.
f2 = foo2()
next(f2) # Prime generator.
while True:
next(f1)
next(f2)
process()
Output:
x
y
x
y
x
...
If you're going to do a lot of this, you can create a decorator that will make generator functions used as coroutines prime themselves automatically (taken from a tutorial David Beazley gave at Pycon 2009 titled Curious Course on Coroutines and Concurrency).
def coroutine(func):
""" Decorator for wrapping coroutine functions so they automatically
prime themselves.
"""
def start(*args,**kwargs):
cr = func(*args,**kwargs)
next(cr)
return cr
return start
#coroutine
def foo1():
while True:
yield
print("x")
#coroutine
def foo2():
while True:
yield
print("y")
# Sample usage.
def process():
f1, f2 = foo1(), foo2() # Each will be "primed" automatically.
for _ in range(10):
next(f1)
next(f2)
So this is my personal way of doing this but there's probably a better one.
def foo(i):
while(True):
i += 1
if(i%2 == 0):
print('x')
else:
print('y')
So the way this works is i is working as an iterator. Then it checks it increments the iterator every time by 1 with i+= 1. Next we check if i is odd or even and because it will alternate. So with every even number you will get x and every odd you you will get y. Hope this helps!
Related
Suppose I wrote a function to create another function, say like:
def g(x):
#do stuff
def h(y):
return x*y
return h
my_func = g(10)
for i in range(100):
print(my_func(i))
In my for loop I am calling my_func a hundred times, however since I only call g once to create my_func I would expect that the #do stuff bit of my code will only run once at the beginning and not once every iteration of the loop.
Can anyone confirm that this is actually the case or will it run every single time inside the for loop? I couldn't find a satisfactory answer elsewhere.
Correct, if there was a line of code where #do stuff is, it would only run once in this example.
Tip: if you had replaced it with print("test") you could have checked this for yourself.
I am using Twisted and making a Looping Call every x seconds.
The function I use for the looping calls makes a return statement.
def f():
# Obtain stuff
return stuff
def main():
LoopingCall(f).start(x)
How can I retrieve the return result of f?
Thanks!
Where do you want to "retrieve" the result of f from? LoopingCall is just called by the reactor, so this question doesn't really make sense. If you want main to somehow access the result that doesn't make sense, because main is run once, but f is run a potentially unlimited number of times.
So perhaps you just want to do this, instead:
def f():
# Obtain stuff
return stuff
def do_something_with_f():
result = f()
do_something(result)
def main():
LoopingCall(do_something_with_f).start(x)
I am working on improving my python and getting up to speed on generators. I have an object that I am working on to process a series of events. I want the list of events to be pulled sequentially and through various methods. I want to use generators for this purpose (I know I can write something else to do this without them).
Here is the sample code that I've been working on:
def _get_next_event():
def gen():
for i,event in enumerate(range(1,10)):
yield event
iterator = gen()
def run():
return iterator
run.next = iterator.__next__
return run
t = _get_next_event()
t.next()
for x in t():
if x < 5:
print(x)
else:
break
t.next()
This lets me do a for loop on the events as well as pull next one individually via function's next method.
I am implementing this in my class, it looks like this:
def _get_next_event(self):
def gen():
print(self.all_sessions)
for event in self.all_sessions:
yield event['event']
iterator = gen()
def run():
return iterator
run.next = iterator.__next__
return run
However, before it works in the class I have to run it, for example before the for loop I have one of these:
self._get_next_event = self._get_next_event()
I think there should be a more elegant way of doing this... what am I missing?
Usually, generators are... not written like that.
Ordinarily, you'd just use yield in the top-level function:
def _get_next_event():
for i,event in enumerate(range(1,10)):
yield event
You can then just write this:
for event in _get_next_event():
# do something with event
Perhaps you had some reason for doing it the way you've shown, but that reason is not evident from the code you've posted.
(for the record, I'm assuming your generator does not literally look like that, or else I'd tell you to change the whole function body to return range(1, 10))
I'm having a hard time wrapping my brain around PEP 380.
What are the situations where yield from is useful?
What is the classic use case?
Why is it compared to micro-threads?
So far I have used generators, but never really used coroutines (introduced by PEP-342). Despite some similarities, generators and coroutines are basically two different concepts. Understanding coroutines (not only generators) is the key to understanding the new syntax.
IMHO coroutines are the most obscure Python feature, most books make it look useless and uninteresting.
Thanks for the great answers, but special thanks to agf and his comment linking to David Beazley presentations.
Let's get one thing out of the way first. The explanation that yield from g is equivalent to for v in g: yield v does not even begin to do justice to what yield from is all about. Because, let's face it, if all yield from does is expand the for loop, then it does not warrant adding yield from to the language and preclude a whole bunch of new features from being implemented in Python 2.x.
What yield from does is it establishes a transparent bidirectional connection between the caller and the sub-generator:
The connection is "transparent" in the sense that it will propagate everything correctly too, not just the elements being generated (e.g. exceptions are propagated).
The connection is "bidirectional" in the sense that data can be both sent from and to a generator.
(If we were talking about TCP, yield from g might mean "now temporarily disconnect my client's socket and reconnect it to this other server socket".)
BTW, if you are not sure what sending data to a generator even means, you need to drop everything and read about coroutines first—they're very useful (contrast them with subroutines), but unfortunately lesser-known in Python. Dave Beazley's Curious Course on Coroutines is an excellent start. Read slides 24-33 for a quick primer.
Reading data from a generator using yield from
def reader():
"""A generator that fakes a read from a file, socket, etc."""
for i in range(4):
yield '<< %s' % i
def reader_wrapper(g):
# Manually iterate over data produced by reader
for v in g:
yield v
wrap = reader_wrapper(reader())
for i in wrap:
print(i)
# Result
<< 0
<< 1
<< 2
<< 3
Instead of manually iterating over reader(), we can just yield from it.
def reader_wrapper(g):
yield from g
That works, and we eliminated one line of code. And probably the intent is a little bit clearer (or not). But nothing life changing.
Sending data to a generator (coroutine) using yield from - Part 1
Now let's do something more interesting. Let's create a coroutine called writer that accepts data sent to it and writes to a socket, fd, etc.
def writer():
"""A coroutine that writes data *sent* to it to fd, socket, etc."""
while True:
w = (yield)
print('>> ', w)
Now the question is, how should the wrapper function handle sending data to the writer, so that any data that is sent to the wrapper is transparently sent to the writer()?
def writer_wrapper(coro):
# TBD
pass
w = writer()
wrap = writer_wrapper(w)
wrap.send(None) # "prime" the coroutine
for i in range(4):
wrap.send(i)
# Expected result
>> 0
>> 1
>> 2
>> 3
The wrapper needs to accept the data that is sent to it (obviously) and should also handle the StopIteration when the for loop is exhausted. Evidently just doing for x in coro: yield x won't do. Here is a version that works.
def writer_wrapper(coro):
coro.send(None) # prime the coro
while True:
try:
x = (yield) # Capture the value that's sent
coro.send(x) # and pass it to the writer
except StopIteration:
pass
Or, we could do this.
def writer_wrapper(coro):
yield from coro
That saves 6 lines of code, make it much much more readable and it just works. Magic!
Sending data to a generator yield from - Part 2 - Exception handling
Let's make it more complicated. What if our writer needs to handle exceptions? Let's say the writer handles a SpamException and it prints *** if it encounters one.
class SpamException(Exception):
pass
def writer():
while True:
try:
w = (yield)
except SpamException:
print('***')
else:
print('>> ', w)
What if we don't change writer_wrapper? Does it work? Let's try
# writer_wrapper same as above
w = writer()
wrap = writer_wrapper(w)
wrap.send(None) # "prime" the coroutine
for i in [0, 1, 2, 'spam', 4]:
if i == 'spam':
wrap.throw(SpamException)
else:
wrap.send(i)
# Expected Result
>> 0
>> 1
>> 2
***
>> 4
# Actual Result
>> 0
>> 1
>> 2
Traceback (most recent call last):
... redacted ...
File ... in writer_wrapper
x = (yield)
__main__.SpamException
Um, it's not working because x = (yield) just raises the exception and everything comes to a crashing halt. Let's make it work, but manually handling exceptions and sending them or throwing them into the sub-generator (writer)
def writer_wrapper(coro):
"""Works. Manually catches exceptions and throws them"""
coro.send(None) # prime the coro
while True:
try:
try:
x = (yield)
except Exception as e: # This catches the SpamException
coro.throw(e)
else:
coro.send(x)
except StopIteration:
pass
This works.
# Result
>> 0
>> 1
>> 2
***
>> 4
But so does this!
def writer_wrapper(coro):
yield from coro
The yield from transparently handles sending the values or throwing values into the sub-generator.
This still does not cover all the corner cases though. What happens if the outer generator is closed? What about the case when the sub-generator returns a value (yes, in Python 3.3+, generators can return values), how should the return value be propagated? That yield from transparently handles all the corner cases is really impressive. yield from just magically works and handles all those cases.
I personally feel yield from is a poor keyword choice because it does not make the two-way nature apparent. There were other keywords proposed (like delegate but were rejected because adding a new keyword to the language is much more difficult than combining existing ones.
In summary, it's best to think of yield from as a transparent two way channel between the caller and the sub-generator.
References:
PEP 380 - Syntax for delegating to a sub-generator (Ewing) [v3.3, 2009-02-13]
PEP 342 -
Coroutines via Enhanced Generators (GvR, Eby) [v2.5, 2005-05-10]
What are the situations where "yield from" is useful?
Every situation where you have a loop like this:
for x in subgenerator:
yield x
As the PEP describes, this is a rather naive attempt at using the subgenerator, it's missing several aspects, especially the proper handling of the .throw()/.send()/.close() mechanisms introduced by PEP 342. To do this properly, rather complicated code is necessary.
What is the classic use case?
Consider that you want to extract information from a recursive data structure. Let's say we want to get all leaf nodes in a tree:
def traverse_tree(node):
if not node.children:
yield node
for child in node.children:
yield from traverse_tree(child)
Even more important is the fact that until the yield from, there was no simple method of refactoring the generator code. Suppose you have a (senseless) generator like this:
def get_list_values(lst):
for item in lst:
yield int(item)
for item in lst:
yield str(item)
for item in lst:
yield float(item)
Now you decide to factor out these loops into separate generators. Without yield from, this is ugly, up to the point where you will think twice whether you actually want to do it. With yield from, it's actually nice to look at:
def get_list_values(lst):
for sub in [get_list_values_as_int,
get_list_values_as_str,
get_list_values_as_float]:
yield from sub(lst)
Why is it compared to micro-threads?
I think what this section in the PEP is talking about is that every generator does have its own isolated execution context. Together with the fact that execution is switched between the generator-iterator and the caller using yield and __next__(), respectively, this is similar to threads, where the operating system switches the executing thread from time to time, along with the execution context (stack, registers, ...).
The effect of this is also comparable: Both the generator-iterator and the caller progress in their execution state at the same time, their executions are interleaved. For example, if the generator does some kind of computation and the caller prints out the results, you'll see the results as soon as they're available. This is a form of concurrency.
That analogy isn't anything specific to yield from, though - it's rather a general property of generators in Python.
Wherever you invoke a generator from within a generator you need a "pump" to re-yield the values: for v in inner_generator: yield v. As the PEP points out there are subtle complexities to this which most people ignore. Non-local flow-control like throw() is one example given in the PEP. The new syntax yield from inner_generator is used wherever you would have written the explicit for loop before. It's not merely syntactic sugar, though: It handles all of the corner cases that are ignored by the for loop. Being "sugary" encourages people to use it and thus get the right behaviors.
This message in the discussion thread talks about these complexities:
With the additional generator features introduced by PEP 342, that is no
longer the case: as described in Greg's PEP, simple iteration doesn't
support send() and throw() correctly. The gymnastics needed to support
send() and throw() actually aren't that complex when you break them
down, but they aren't trivial either.
I can't speak to a comparison with micro-threads, other than to observe that generators are a type of paralellism. You can consider the suspended generator to be a thread which sends values via yield to a consumer thread. The actual implementation may be nothing like this (and the actual implementation is obviously of great interest to the Python developers) but this does not concern the users.
The new yield from syntax does not add any additional capability to the language in terms of threading, it just makes it easier to use existing features correctly. Or more precisely it makes it easier for a novice consumer of a complex inner generator written by an expert to pass through that generator without breaking any of its complex features.
A short example will help you understand one of yield from's use case: get value from another generator
def flatten(sequence):
"""flatten a multi level list or something
>>> list(flatten([1, [2], 3]))
[1, 2, 3]
>>> list(flatten([1, [2], [3, [4]]]))
[1, 2, 3, 4]
"""
for element in sequence:
if hasattr(element, '__iter__'):
yield from flatten(element)
else:
yield element
print(list(flatten([1, [2], [3, [4]]])))
yield from basically chains iterators in a efficient way:
# chain from itertools:
def chain(*iters):
for it in iters:
for item in it:
yield item
# with the new keyword
def chain(*iters):
for it in iters:
yield from it
As you can see it removes one pure Python loop. That's pretty much all it does, but chaining iterators is a pretty common pattern in Python.
Threads are basically a feature that allow you to jump out of functions at completely random points and jump back into the state of another function. The thread supervisor does this very often, so the program appears to run all these functions at the same time. The problem is that the points are random, so you need to use locking to prevent the supervisor from stopping the function at a problematic point.
Generators are pretty similar to threads in this sense: They allow you to specify specific points (whenever they yield) where you can jump in and out. When used this way, generators are called coroutines.
Read this excellent tutorials about coroutines in Python for more details
In applied usage for the Asynchronous IO coroutine, yield from has a similar behavior as await in a coroutine function. Both of which is used to suspend the execution of coroutine.
yield from is used by the generator-based coroutine.
await is used for async def coroutine. (since Python 3.5+)
For Asyncio, if there's no need to support an older Python version (i.e. >3.5), async def/await is the recommended syntax to define a coroutine. Thus yield from is no longer needed in a coroutine.
But in general outside of asyncio, yield from <sub-generator> has still some other usage in iterating the sub-generator as mentioned in the earlier answer.
yield will yields single value into collection.
yield from will yields collection into collection and make it flatten.
Check this example:
def yieldOnly():
yield "A"
yield "B"
yield "C"
def yieldFrom():
for i in [1, 2, 3]:
yield from yieldOnly()
test = yieldFrom()
for i in test:
print(i)
In console you will see:
A
B
C
A
B
C
A
B
C
This code defines a function fixed_sum_digits returning a generator enumerating all six digits numbers such that the sum of digits is 20.
def iter_fun(sum, deepness, myString, Total):
if deepness == 0:
if sum == Total:
yield myString
else:
for i in range(min(10, Total - sum + 1)):
yield from iter_fun(sum + i,deepness - 1,myString + str(i),Total)
def fixed_sum_digits(digits, Tot):
return iter_fun(0,digits,"",Tot)
Try to write it without yield from. If you find an effective way to do it let me know.
I think that for cases like this one: visiting trees, yield from makes the code simpler and cleaner.
Simply put, yield from provides tail recursion for iterator functions.
yield from yields from a generator until the generator is empty, and then continue executing following lines of codes.
e.g.
def gen(sequence):
for i in sequence:
yield i
def merge_batch(sub_seq):
yield {"data": sub_seq}
def modified_gen(g, batch_size):
stream = []
for i in g:
stream.append(i)
stream_len = len(stream)
if stream_len == batch_size:
yield from merge_batch(stream)
print("batch ends")
stream = []
stream_len = 0
running this gives you:
In [17]: g = gen([1,2,3,4,5,6,7,8,9,10])
In [18]: mg = modified_gen(g, 2)
In [19]: next(mg)
Out[19]: {'data': [1, 2]}
In [20]: next(mg)
batch ends
Out[20]: {'data': [3, 4]}
In [21]: next(mg)
batch ends
Out[21]: {'data': [5, 6]}
In [22]: next(mg)
batch ends
Out[22]: {'data': [7, 8]}
In [23]: next(mg)
batch ends
Out[23]: {'data': [9, 10]}
In [24]: next(mg)
batch ends
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
Input In [24], in <cell line: 1>()
----> 1 next(mg)
StopIteration:
So, yield from can take outputs from another generator, do some modification, and then feed its own output to others as a generator itself.
That in my humble opinion, is one of the main use cases of yield from
At the moment, I'm doing stuff like the following, which is getting tedious:
run_once = 0
while 1:
if run_once == 0:
myFunction()
run_once = 1:
I'm guessing there is some more accepted way of handling this stuff?
What I'm looking for is having a function execute once, on demand. For example, at the press of a certain button. It is an interactive app which has a lot of user controlled switches. Having a junk variable for every switch, just for keeping track of whether it has been run or not, seemed kind of inefficient.
I would use a decorator on the function to handle keeping track of how many times it runs.
def run_once(f):
def wrapper(*args, **kwargs):
if not wrapper.has_run:
wrapper.has_run = True
return f(*args, **kwargs)
wrapper.has_run = False
return wrapper
#run_once
def my_function(foo, bar):
return foo+bar
Now my_function will only run once. Other calls to it will return None. Just add an else clause to the if if you want it to return something else. From your example, it doesn't need to return anything ever.
If you don't control the creation of the function, or the function needs to be used normally in other contexts, you can just apply the decorator manually as well.
action = run_once(my_function)
while 1:
if predicate:
action()
This will leave my_function available for other uses.
Finally, if you need to only run it once twice, then you can just do
action = run_once(my_function)
action() # run once the first time
action.has_run = False
action() # run once the second time
Another option is to set the func_code code object for your function to be a code object for a function that does nothing. This should be done at the end of your function body.
For example:
def run_once():
# Code for something you only want to execute once
run_once.func_code = (lambda:None).func_code
Here run_once.func_code = (lambda:None).func_code replaces your function's executable code with the code for lambda:None, so all subsequent calls to run_once() will do nothing.
This technique is less flexible than the decorator approach suggested in the accepted answer, but may be more concise if you only have one function you want to run once.
Run the function before the loop. Example:
myFunction()
while True:
# all the other code being executed in your loop
This is the obvious solution. If there's more than meets the eye, the solution may be a bit more complicated.
I'm assuming this is an action that you want to be performed at most one time, if some conditions are met. Since you won't always perform the action, you can't do it unconditionally outside the loop. Something like lazily retrieving some data (and caching it) if you get a request, but not retrieving it otherwise.
def do_something():
[x() for x in expensive_operations]
global action
action = lambda : None
action = do_something
while True:
# some sort of complex logic...
if foo:
action()
There are many ways to do what you want; however, do note that it is quite possible that —as described in the question— you don't have to call the function inside the loop.
If you insist in having the function call inside the loop, you can also do:
needs_to_run= expensive_function
while 1:
…
if needs_to_run: needs_to_run(); needs_to_run= None
…
I've thought of another—slightly unusual, but very effective—way to do this that doesn't require decorator functions or classes. Instead it just uses a mutable keyword argument, which ought to work in most versions of Python. Most of the time these are something to be avoided since normally you wouldn't want a default argument value to change from call-to-call—but that ability can be leveraged in this case and used as a cheap storage mechanism. Here's how that would work:
def my_function1(_has_run=[]):
if _has_run: return
print("my_function1 doing stuff")
_has_run.append(1)
def my_function2(_has_run=[]):
if _has_run: return
print("my_function2 doing some other stuff")
_has_run.append(1)
for i in range(10):
my_function1()
my_function2()
print('----')
my_function1(_has_run=[]) # Force it to run.
Output:
my_function1 doing stuff
my_function2 doing some other stuff
----
my_function1 doing stuff
This could be simplified a little further by doing what #gnibbler suggested in his answer and using an iterator (which were introduced in Python 2.2):
from itertools import count
def my_function3(_count=count()):
if next(_count): return
print("my_function3 doing something")
for i in range(10):
my_function3()
print('----')
my_function3(_count=count()) # Force it to run.
Output:
my_function3 doing something
----
my_function3 doing something
Here's an answer that doesn't involve reassignment of functions, yet still prevents the need for that ugly "is first" check.
__missing__ is supported by Python 2.5 and above.
def do_once_varname1():
print 'performing varname1'
return 'only done once for varname1'
def do_once_varname2():
print 'performing varname2'
return 'only done once for varname2'
class cdict(dict):
def __missing__(self,key):
val=self['do_once_'+key]()
self[key]=val
return val
cache_dict=cdict(do_once_varname1=do_once_varname1,do_once_varname2=do_once_varname2)
if __name__=='__main__':
print cache_dict['varname1'] # causes 2 prints
print cache_dict['varname2'] # causes 2 prints
print cache_dict['varname1'] # just 1 print
print cache_dict['varname2'] # just 1 print
Output:
performing varname1
only done once for varname1
performing varname2
only done once for varname2
only done once for varname1
only done once for varname2
One object-oriented approach and make your function a class, aka as a "functor", whose instances automatically keep track of whether they've been run or not when each instance is created.
Since your updated question indicates you may need many of them, I've updated my answer to deal with that by using a class factory pattern. This is a bit unusual, and it may have been down-voted for that reason (although we'll never know for sure because they never left a comment). It could also be done with a metaclass, but it's not much simpler.
def RunOnceFactory():
class RunOnceBase(object): # abstract base class
_shared_state = {} # shared state of all instances (borg pattern)
has_run = False
def __init__(self, *args, **kwargs):
self.__dict__ = self._shared_state
if not self.has_run:
self.stuff_done_once(*args, **kwargs)
self.has_run = True
return RunOnceBase
if __name__ == '__main__':
class MyFunction1(RunOnceFactory()):
def stuff_done_once(self, *args, **kwargs):
print("MyFunction1.stuff_done_once() called")
class MyFunction2(RunOnceFactory()):
def stuff_done_once(self, *args, **kwargs):
print("MyFunction2.stuff_done_once() called")
for _ in range(10):
MyFunction1() # will only call its stuff_done_once() method once
MyFunction2() # ditto
Output:
MyFunction1.stuff_done_once() called
MyFunction2.stuff_done_once() called
Note: You could make a function/class able to do stuff again by adding a reset() method to its subclass that reset the shared has_run attribute. It's also possible to pass regular and keyword arguments to the stuff_done_once() method when the functor is created and the method is called, if desired.
And, yes, it would be applicable given the information you added to your question.
Assuming there is some reason why myFunction() can't be called before the loop
from itertools import count
for i in count():
if i==0:
myFunction()
Here's an explicit way to code this up, where the state of which functions have been called is kept locally (so global state is avoided). I don't much like the non-explicit forms suggested in other answers: it's too surprising to see f() and for this not to mean that f() gets called.
This works by using dict.pop which looks up a key in a dict, removes the key from the dict, and takes a default value to use in case the key isn't found.
def do_nothing(*args, *kwargs):
pass
# A list of all the functions you want to run just once.
actions = [
my_function,
other_function
]
actions = dict((action, action) for action in actions)
while True:
if some_condition:
actions.pop(my_function, do_nothing)()
if some_other_condition:
actions.pop(other_function, do_nothing)()
I use cached_property decorator from functools to run just once and save the value. Example from the official documentation https://docs.python.org/3/library/functools.html
class DataSet:
def __init__(self, sequence_of_numbers):
self._data = tuple(sequence_of_numbers)
#cached_property
def stdev(self):
return statistics.stdev(self._data)
You can also use one of the standard library functools.lru_cache or functools.cache decorators in front of the function:
from functools import lru_cache
#lru_cache
def expensive_function():
return None
https://docs.python.org/3/library/functools.html
If I understand the updated question correctly, something like this should work
def function1():
print "function1 called"
def function2():
print "function2 called"
def function3():
print "function3 called"
called_functions = set()
while True:
n = raw_input("choose a function: 1,2 or 3 ")
func = {"1": function1,
"2": function2,
"3": function3}.get(n)
if func in called_functions:
print "That function has already been called"
else:
called_functions.add(func)
func()
You have all those 'junk variables' outside of your mainline while True loop. To make the code easier to read those variables can be brought inside the loop, right next to where they are used. You can also set up a variable naming convention for these program control switches. So for example:
# # _already_done checkpoint logic
try:
ran_this_user_request_already_done
except:
this_user_request()
ran_this_user_request_already_done = 1
Note that on the first execution of this code the variable ran_this_user_request_already_done is not defined until after this_user_request() is called.
A simple function you can reuse in many places in your code (based on the other answers here):
def firstrun(keyword, _keys=[]):
"""Returns True only the first time it's called with each keyword."""
if keyword in _keys:
return False
else:
_keys.append(keyword)
return True
or equivalently (if you like to rely on other libraries):
from collections import defaultdict
from itertools import count
def firstrun(keyword, _keys=defaultdict(count)):
"""Returns True only the first time it's called with each keyword."""
return not _keys[keyword].next()
Sample usage:
for i in range(20):
if firstrun('house'):
build_house() # runs only once
if firstrun(42): # True
print 'This will print.'
if firstrun(42): # False
print 'This will never print.'
I've taken a more flexible approach inspired by functools.partial function:
DO_ONCE_MEMORY = []
def do_once(id, func, *args, **kwargs):
if id not in DO_ONCE_MEMORY:
DO_ONCE_MEMORY.append(id)
return func(*args, **kwargs)
else:
return None
With this approach you are able to have more complex and explicit interactions:
do_once('foobar', print, "first try")
do_once('foo', print, "first try")
do_once('bar', print, "second try")
# first try
# second try
The exciting part about this approach it can be used anywhere and does not require factories - it's just a small memory tracker.
Depending on the situation, an alternative to the decorator could be the following:
from itertools import chain, repeat
func_iter = chain((myFunction,), repeat(lambda *args, **kwds: None))
while True:
next(func_iter)()
The idea is based on iterators, which yield the function once (or using repeat(muFunction, n) n-times), and then endlessly the lambda doing nothing.
The main advantage is that you don't need a decorator which sometimes complicates things, here everything happens in a single (to my mind) readable line. The disadvantage is that you have an ugly next in your code.
Performance wise there seems to be not much of a difference, on my machine both approaches have an overhead of around 130 ns.
If the condition check needs to happen only once you are in the loop, having a flag signaling that you have already run the function helps. In this case you used a counter, a boolean variable would work just as fine.
signal = False
count = 0
def callme():
print "I am being called"
while count < 2:
if signal == False :
callme()
signal = True
count +=1
I'm not sure that I understood your problem, but I think you can divide loop. On the part of the function and the part without it and save the two loops.