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.:
class DataLogger(object):
def __init__(self):
# do init stuff
def startlog(self, t):
# start the log
class Heater(DataLogger):
def __init__(self):
# do some stuff before initing your dataLogger
super(Heater, self).__init__() # init the DataLogger
#other functions
that way you can just do:
h1 = Heater()
h1.startlog(5)
h1.do_other_stuff()
An example that uses it as a mixin for an existing class:
class DataLoggerMixin(object):
def __init__(self):
# do your init things
super(DataLogger, this).__init__() # this will trigger the next __init__ call in the inheritance chain (i.e. whatever you mix it with)
class Heater(object):
""" Here's a heater you have lying around that doesn't do data logging. No need to change it."""
# add a new child class with 2 lines, that includes the DataLoggerMixin as the first parent class, and you will have a new class with all the DataLogging functionality and the Heater functionality.
class LoggingHeater(DataLoggerMixin, Heater):
""" Now its a data logging heater """
pass # no further code should be necessary if you list DataLoggerMixin first in the base classes.
>>> logging_heater = LoggingHeater()
>>> logging_heater.start_log(5)
>>> logging_heater.do_heater_stuff()
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:
class DataLogger(object)
def __init__(self, object_to_log)
self.object = object_to_log # now you have access to self.object in all your methods.
# Record measurements and controls in a database
def start(self,t)
# Starts a new thread to aqcuire and reccord measuements every t secconds
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:
h1 = Heater()
log = DataLogger(h1)
log.start(60)
h1.set_power(10,100)
h1.turn_on()
sleep(10)
h1.turn_off()
Hope this helps!