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