[Tutor] automatic setting of class property when another one changes

Peter Otten __peter__ at web.de
Thu Sep 15 08:14:33 EDT 2016


ingo wrote:

> Rather stuck with this one, I'd like to automatically (re)set the
> propery "relaystate" when one of the others (Tm, Tset, Th) is set,
> regardless of wether their value has changed.

The easiest way to achieve your goal seems to be a read-only property:

# this creates a class that should be shared by all RelayState instances;
# therefore it belongs on the module level
RelayState = namedtuple('RelayState', ['heat', 'cool'])

# the states are immutable and can safely be defined outside the method
HEAT = rlstate(1, 0)
COOL = rlstate(0, 1)
OFF = rlstate(0, 0)

class Thermostat():
    ...

    @property
    def relaystate(self):
        logger.debug("GETTER relaystate")
        lower = self.Tset - self.Th
        upper = self.Tset + self.Th
        if self.Tm < lower:
            return HEAT
        elif self.Tm > upper:
            return COOL
        else:
            return OFF


If that doesn't work (because you want to operate an actual relay, say) you 
probably have to trigger a change in the TXXX setters:

class Thermostat():

    def __init__(self, Tm=20, Tset=20, Th=0.3):
        self._relaystate = None
        self.Tm = Tm
        self.Tset = Tset
        self.Th = Th

    def update_relaystate(self):
        try:
            state = self.calculate_relaystate()
        except AttributeError:
            pass
        else:
            self.relaystate = state

    @property
    def Tm(self):
        logger.debug("GETTER Tm")
        return self._Tm

    @Tm.setter
    def Tm(self, value):
        logger.debug("SETTER Tm")
        self._Tm = value
        self.update_relaystate()

    ...

    @property
    def relaystate(self):
        logger.debug("GETTER relaystate")
        return self._relaystate

    @relaystate.setter
    def relaystate(self, value):
        if value != self.relaystate:
            logger.debug(
                "SWITCHING relaystate from %s to %s", 
                self.relaystate, value)
            self._relaystate = value

    def calculate_relaystate(self):
        lower = self.Tset-self.Th
        upper = self.Tset+self.Th
        if self.Tm < lower:
            return HEAT
        elif self.Tm > upper:
            return COOL
        else:
            return OFF



> 
> Ingo
> 
> My code so far:
> 
> from collections import namedtuple
> import logging
> 
> logger = logging.getLogger()
> logger.setLevel(logging.DEBUG)
> stream_handler = logging.StreamHandler()
> stream_handler.setLevel(logging.DEBUG)
> formatter = logging.Formatter(
>      '[%(levelname)-8s] %(asctime)s (%(name)-8s) - %(message)s',
>      '%Y-%m-%d %H:%M:%S',
> )
> stream_handler.setFormatter(formatter)
> logger.addHandler(stream_handler)
> 
> 
> class Thermostat():
>      def __init__(self, Tm=20, Tset=20, Th=0.3):
>          logger.debug("__INIT__")
>          self.Tm = Tm
>          self.Tset = Tset
>          self.Th = Th
>          self.relaystate = None
> 
>      @property
>      def Tm(self):
>          logger.debug("GETTER Tm")
>          return self._Tm
>      @Tm.setter
>      def Tm(self, value):
>          logger.debug("SETTER Tm")
>          self._Tm = value
> 
>      @property
>      def Tset(self):
>          logger.debug("GETTER Tset")
>          return self._Tset
>      @Tset.setter
>      def Tset(self, value):
>          logger.debug("SETTER Tset")
>          self._Tset = value
> 
>      @property
>      def Th(self):
>          logger.debug("GETTER Th")
>          return self._Th
>      @Th.setter
>      def Th(self, value):
>          logger.debug("SETTER Th")
>          self._Th = value
> 
>      @property
>      def relaystate(self):
>          logger.debug("GETTER relaystate")
>          return self._relaystate
>      @relaystate.setter
>      def relaystate(self, value):
>          logger.debug("SETTER relaystate")
>          #on init while setting Tm, Tset and Th are not known
>          #so relaystate can not be calculated
>          try:
>              lower = self.Tset-self.Th
>              upper = self.Tset+self.Th
>          except AttributeError as e:
>              logger.debug("SETTER relaystate : %s", e)
>              self._relaystate = None
>          rlstate = namedtuple('relaystate', ['heat', 'cool'])
>          if self.Tm < lower:
>              value = rlstate(1,0)
>          elif self.Tm > upper:
>              value = rlstate(0,1)
>          elif self.Tm > lower and self.Tm < upper:
>              value = rlstate(0,0)
>          self._relaystate = value
> 
> 
> if __name__ == "__main__":
> 
>      TS1 = Thermostat()
>      TS1.Tset = 44
>      print("heat : ",TS1.relaystate.heat,"cool : ",TS1.relaystate.cool)
> 
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor




More information about the Tutor mailing list