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

2016-09-15 Thread Steven D'Aprano
On Thu, Sep 15, 2016 at 12:30:34PM +0200, 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 obvious way is to make Tm, etc properties, and have their setter 
method reset the relaystate property. Since they relay state cannot be 
calculated during __init__ until all of the properties have been set, 
simply bypass the properties in the __init__. See below.


> My code so far:

Thanks for showing your code, but you shouldn't drown us in masses of 
irrelevant code that has nothing to do with your problem. We don't care 
about the logging code you show. Take it out. In fact, the best way to 
demo code is to cut it down to the barest minimum demonstrating the 
problem:


class Thermostat(object):
def __init__(self, Tm):
self._Tm = Tm
self.reset_relay()

@property
def Tm(self):
return self._Tm
@Tm.setter
def Tm(self, value):
self.reset_relay()
self._Tm = value

def reset_relay():
self.relaystate = None


About a dozen lines, versus seventy for your code.

See also this for more information:
http://sscce.org/


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


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

2016-09-15 Thread Peter Otten
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@python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:

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

2016-09-15 Thread ingo
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.


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@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor