How to combine two functions together
I have a class controlling some hardware:
class Heater()
def set_power(self,dutycycle, period)
...
def turn_on(self)
...
def turn_off(self)
And a class that connects to a database and handles all data logging functionality for an experiment:
class DataLogger()
def __init__(self)
# Record measurements and controls in a database
def start(self,t)
# Starts a new thread to acquire and record measuements every t seconds
Now, in my program recipe.py I want to do something like:
log = DataLogger()
@DataLogger_decorator
H1 = Heater()
log.start(60)
H1.set_power(10,100)
H1.turn_on()
sleep(10)
H1.turn_off()
etc
Where all actions on H1 are recorded by the datalogger. I can change any of the classes involved, just looking for an elegant way to do this. Ideally the hardware functions remain separated from the database and DataLogger functions. And ideally the DataLogger is reusable for other controls and measurements.
For this scenario, I prefer using DataLogger as a BaseClass or Mixin for other classes rather than trying to do some sort of decorator magic (which doesn’t really click for me as a pythonic way to use a decorator)
e.g.:
that way you can just do:
An example that uses it as a mixin for an existing class:
The key with successfully using mixins in python is to understand how the method resolution order (MRO), particularly for super, works in a multiple inheritance situation. See this on cooperative multiple inheritance.
Alternative Method: Use a Wrapper Class
If Mixin methodology doesn’t work for your scheme, another option would be to use DataLogger as a wrapper class for objects to be logged. Basically Data Logger would accept an object to do logging on in its constructor like so:
I’m not sure what type of logging or monitoring is done and whether you need access to the object you’re logging or if it is independent. If the former, presumably Heater, Valve, etc. all implement the same functions that DataLogger cares about so you can Log for them regardless of what class they are. (This is a handy core feature of dynamic languages like Python called “Duck typing”, where you can operate on different types, as long as the types implement the functions or attributes you care about. “if it quacks like a duck . . .”)
Your code might look more like this, using wrapper class methodology:
Hope this helps!