I have a few logical processes implemented in the same class.
A class instance get a generator for each process, and run()
advances said generators. In my case generators don't end.
How would you call foo_function and foo_object in the code below
class C(threading.Thread):
def foo_function(self):
""" generator *function*,
logical process foo """
while True:
# some state checks
if self.some_attr:
# side-effects here
pass
yield
def __init__(self):
# generator *object*
# i.e. process instance
self.foo_object = self.foo_function() # <- here
def run(self):
while True:
next(self.foo_object)
next(self.another_object)
if xxx:
next(self.yet_another_object)
Typical processes are discovery
, authentication
, watchdog
, etc.
How can I name function that defines the generator and the attribute that contains generator object in a sensible way?
Finally just for the kicks, same name name would be insane, right?
class C:
def foo(self):
yield 1; yield 2
def __init__(self):
self.foo = self.foo()
c = C()
type(C.foo) is function
type(c.foo) is generator
Python generators are a simple way of creating iterators. All the work we mentioned above are automatically handled by generators in Python. Simply speaking, a generator is a function that returns an object (iterator) which we can iterate over (one value at a time).
Function names should be lowercase, with words separated by underscores as necessary to improve readability.
You need to call next() or loop through the generator object to access the values produced by the generator expression. When there isn't the next value in the generator object, a StopIteration exception is thrown. A for loop can be used to iterate the generator object.
You could make the members containing generators be created automatically from the function's name, using some kind of covention designed by your self. For instance, in my convention all generators will be contained by a member called: <function_name>_gen
.
I would call the function name as its responsability: discovery
, authentication
and watchdog
are good names. So you only need a way to automatically set: self.discovery_gen
, self.authentication_gen
and self.watchdog_gen
.
Code sample:
class C:
def discovery(self):
yield 1; yield 2
# Register all the functions for wich you want to have a generator
# object.
REGISTERED_GEN_FUNCTIONS = [discovery]
def __init__(self):
for func in self.REGISTERED_GEN_FUNCTIONS:
name = func.__name__
# All generators objects will be called <function_name>_gen.
setattr(self, "{0}_gen".format(name), getattr(self, name)())
a = C()
for i in a.discovery_gen:
print(i)
Ouput
>>> 1
>>> 2
If the generators are only accessed inside the run
method you can do something like this:
class C:
def a_process(self):
while True: yield
def another_process(self):
while True: yield
def run(self):
# Use itertools.izip in python 2
for _ in zip(a_process(), another_process()):
pass
Here, zip
and the for loop will create and advance the generators automatically. This way, you don't need to keep track of them.
If you need access to the generators outside the run
method, you can create an ordered dictionary of generators (in case the generators need to be advanced in a defined order):
from collections import OrderedDict
class C:
# Processes here
def __init__(self):
self.generators = OrderedDict()
for gn in ('a_process', 'another_process'):
self.generators[gn] = getattr(self, gn)()
def run(self):
while True:
for g in self.generators.values():
next(g)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With