accessor/mutator functions
Dan Sommers
me at privacy.net
Mon Feb 28 18:49:39 EST 2005
On Mon, 28 Feb 2005 23:08:04 GMT,
Andrew Dalke <dalke at dalkescientific.com> wrote:
> On Mon, 28 Feb 2005 15:50:22 -0500, Dan Sommers wrote:
>> The reason their code is so inflexible is that they've filled their
>> classes with boiler plate get/set methods.
>>
>> Why do users of classes need such access anyway? If my class performs
>> useful functions and returns useful results, no user of my class should
>> care about its attributes. If I "have to" allow access to my attributes
>> in order that my users be happy, then I did something else wrong when I
>> designed the class and its public interface in the first place.
> Consider an interface to a temperature controller. It will
> have several properties:
> - current temperature (read only)
> - target temperature (read/write)
> - various tuning parameters that affect the rate of change,
> stability, etc.; eg, lookup details on a PID controller
> These are properties of the temperature controller object.
> In Python these properties are traditionally mapped to attributes.
> Under languages that don't have a __getattr__/"property" mechanism
> for separating interface from implementation these are implemented
> via get/set accessor methods.
> It is very often useful to change the temperature setting of
> a controller over time. Eg, a chemical protocol might say
> "warm from 50 to 80 over a period of 30 minutes, 1 degree
> per minute".
> In Python that might be written as:
> temp_controller = TemperatureController("/dev/com3")
> temp_controller.target = 50
> print "Bringing reactor to", temp_controller.target
> while 1:
> print "Current temperature is", temp_controller.current
> if abs(temp_controller.current - temp_controller.target) < 0.1:
> break
> time.sleep(30)
> raw_input("Insert sample and press the <enter> key: ")
> for temp in range(51, 81):
> print "Raising reactor temperature to", temp
> temp_controller.target = temp
> time.sleep(60)
> if abs(temp_controller.current - temp) > 0.1:
> print "Variance too high!", temp_controller.current
> print "DONE!"
> What's wrong with the use of attributes in this case and how
> would you write your interface?
I think I'd add a change_temperature_to method that accepts the target
temperature and some sort of timing information, depending on how the
rest of the program and/or thread is structured. It might turn into two
or three methods, depending on whether I can afford to block while
waiting, or what kind of intermediate feedback and/or error handling I
want (or one method with some carefully chosen default arguments). I
don't know how that device driver works, but it might look something
like this:
def change_temperature_to( self, target, seconds_between_checks ):
print 'target temperature:', target
tell_the_device_to_change( )
while 1:
current = read_the_temperature_from_the_device( )
print 'current temperature:', current
if abs( current - target ) < 0.1:
break
time.sleep( seconds_between_checks )
Obviously, that code is untested! ;-)
In the case of simply reading the current temperature, and not knowing
what's inside that device driver, I'd still lean away from exposing a
current temperature attribute directly. I think part of my thinking
comes from my old Pascal days, when it made me cringe to think that
"x:=b;" might actually execute a subroutine rather than just copy some
memory around.
I'm not saying that my applications *never* access my objects'
attributes directly, just that it's one of those things that raises at
least a yellow flag in my mind.
Regards,
Dan
--
Dan Sommers
<http://www.tombstonezero.net/dan/>
μ₀ × ε₀ × c² = 1
More information about the Python-list
mailing list