FAQ
When I look at how classes are set up in other languages (e.g. C++), I
often observe the following patterns:
1) for each data member, the class will have an accessor member
function (a Get<whatever> function)
2) for each data member, the class will have a mutator member function
(a Set<whatver> function)
3) data members are never referenced directly; they are always
referenced with the accessor and mutator functions

My questions are:
a) Are the three things above considered pythonic?
b) What are the tradeoffs of using getattr() and setattr() rather than
creating accessor and mutator functions for each data member?

Search Discussions

  • Michael Spencer at Feb 25, 2005 at 8:11 am

    mirandacascade at yahoo.com wrote:
    When I look at how classes are set up in other languages (e.g. C++), I
    often observe the following patterns:
    1) for each data member, the class will have an accessor member
    function (a Get<whatever> function)
    2) for each data member, the class will have a mutator member function
    (a Set<whatver> function)
    3) data members are never referenced directly; they are always
    referenced with the accessor and mutator functions

    My questions are:
    a) Are the three things above considered pythonic? No
    b) What are the tradeoffs of using getattr() and setattr() rather than
    creating accessor and mutator functions for each data member?
    Use property descriptors instead:
    http://www.python.org/2.2.1/descrintro.html#property
    http://users.rcn.com/python/download/Descriptor.htm#properties

    Michael
  • Simon Wittber at Feb 25, 2005 at 8:53 am

    My questions are:
    a) Are the three things above considered pythonic?
    Python uses a function called 'property to achieve the same effect.
    This example is taken from the documentation:

    class C(object):
    def __init__(self):
    self.__x = 0
    def getx(self):
    return self.__x
    def setx(self, x):
    if x < 0: x = 0
    self.__x = x
    x = property(getx, setx)


    In the above example, "C().x" would invoke and return the result of
    .getx (the accessor), and "C().x = 10" would invoke .setx (the
    mutator).

    Are they considered Pythonic? Well, It depends on how they are used.
    If you are using properties to perform some kind of type checking...
    then the answer is probably No.

    I've found that they are quite useful for implementing lazy evaluation
    of attributes, which I would consider quite Pythonic.

    Sw.
  • Mirandacascade at Feb 25, 2005 at 3:54 pm
    If the class had two attributes--x and y--would the code look like
    something lik this:

    class C(object):
    def __init__(self):
    self.__x = 0
    self.__y = 0
    def getx(self):
    return self.__x
    def setx(self, x):
    if x < 0: x = 0
    self.__x = x
    def gety(self):
    return self.__y
    def sety(self, y):
    if y < 0: y = 0
    self.__y = y
    x = property(getx, setx)
    y = property(gety, sety)

    ?

    Because if so, does the term 'lazy evaluation' refer to the fact that
    instead of:

    C().getx()
    C().gety()
    C().setx(10)
    C().sety(10)

    one would substitute:

    C().x
    C().y
    C().x = 10
    C().y = 10

    ?
  • Diez B. Roggisch at Feb 25, 2005 at 4:11 pm

    Because if so, does the term 'lazy evaluation' refer to the fact that
    instead of:
    No, it is a common technical term. It means that a value is computed the
    time it is requested for the first time.

    Like this:

    class Foo(object):

    def __init__(self):
    self.__bar = None

    def getBar(self):
    if self.__bar is None:
    self.__bar = some_lengthy_computation()
    return self.__bar


    That you can make bar a property of Foo is unrelated to this.

    Another reason to use properties is if the value is always or at least
    frequently a freshly computed one.


    --
    Regards,

    Diez B. Roggisch
  • Michael Spencer at Feb 25, 2005 at 6:03 pm

    mirandacascade at yahoo.com wrote:
    If the class had two attributes--x and y--would the code look like
    something lik this:

    class C(object):
    def __init__(self):
    self.__x = 0
    self.__y = 0
    def getx(self):
    return self.__x
    def setx(self, x):
    if x < 0: x = 0
    self.__x = x
    def gety(self):
    return self.__y
    def sety(self, y):
    if y < 0: y = 0
    self.__y = y
    x = property(getx, setx)
    y = property(gety, sety)
    It could do - that works. One feature of this solution is that it leaves the
    accessor/mutator functions in the namespace. That may be a good or a bad thing.
    If bad, you could simply delete them after the property call (which is
    probably better written as close as possible to the functions)

    i.e., class C(object):
    def __init__(self):
    self.__x = 0
    self.__y = 0
    def getx(self):
    return self.__x
    def setx(self, x):
    if x < 0: x = 0
    self.__x = x
    x = property(getx, setx)
    del getx, setx
    def gety(self):
    return self.__y
    def sety(self, y):
    if y < 0: y = 0
    self.__y = y
    y = property(gety, sety)
    del gety, sety

    There are also recipes in the cookbook for defining property "suites" more elegantly

    Note, that it is also easy to "roll your own" descriptor, which may be
    worthwhile if you have a lot of similar properties, for example (not tested
    beyond what you see):

    from weakref import WeakKeyDictionary

    class Property(object):
    def __init__(self, adapter):
    """adapter is a single argument function that will be
    applied to the value before setting it"""
    self.objdict = WeakKeyDictionary()
    self.adapter = adapter
    def __get__(self, obj, cls):
    if isinstance(obj, cls):
    return self.objdict[obj]
    else:
    return self
    def __set__(self, obj, value):
    self.objdict[obj] = self.adapter(value)

    class C(object):
    x = Property(lambda val: max(val, 0))
    y = Property(lambda val: val%2)
    z = Property(abs)
    c= C()
    c.x = -3
    c.x
    c.y = -3
    c.y
    1
    c.z = -3
    c.z
    3
    >>>


    Michael
  • Terry Reedy at Feb 25, 2005 at 5:47 pm
    <mirandacascade at yahoo.com> wrote in message
    news:1109315698.002207.245690 at g14g2000cwa.googlegroups.com...
    When I look at how classes are set up in other languages (e.g. C++), I
    often observe the following patterns:
    1) for each data member, the class will have an accessor member
    function (a Get<whatever> function)
    2) for each data member, the class will have a mutator member function
    (a Set<whatver> function)
    3) data members are never referenced directly; they are always
    referenced with the accessor and mutator functions

    My questions are:
    a) Are the three things above considered pythonic?
    As others have said, 'no', as in 'unnecessary because we have a better way
    to accomplish the same purpose without doubling the attribute namespace'.
    The purpose of the pattern is to hide the specific implementation of a
    class (which attributes are static and which dynamic) and to allow that
    implementation to change without changing programs that use the class.
    Consider a complex class with interdependent .real, .imag, .rad, and .theta
    attributes and the possible behind-the-scene implementations for what is
    kept static and how they are kept synchronized. The need for get/set to
    accomplish this in C++ arises from the fact that attribute names are
    resolved at compile time, so that x.a syntax can only be used for simple
    static attributes and access. Python, on the other hand, has means to
    'magically' map what looks like direct attribute access into a function
    call. First there was __get/setattr__ (which is awkward for multiple
    dynamic attributes) and now properties with get/set/del for individual
    dynamic attributes.
    b) What are the tradeoffs of using getattr() and setattr() rather than
    creating accessor and mutator functions for each data member?

    --
    http://mail.python.org/mailman/listinfo/python-list
  • Nick Craig-Wood at Feb 28, 2005 at 10:30 am

    Michael Spencer wrote:
    mirandacascade at yahoo.com wrote:
    When I look at how classes are set up in other languages (e.g. C++), I
    often observe the following patterns:
    1) for each data member, the class will have an accessor member
    function (a Get<whatever> function)
    2) for each data member, the class will have a mutator member function
    (a Set<whatver> function)
    3) data members are never referenced directly; they are always
    referenced with the accessor and mutator functions

    My questions are:
    a) Are the three things above considered pythonic? No
    b) What are the tradeoffs of using getattr() and setattr() rather than
    creating accessor and mutator functions for each data member?
    Use property descriptors instead:
    http://www.python.org/2.2.1/descrintro.html#property
    http://users.rcn.com/python/download/Descriptor.htm#properties
    Actually I would say just access the attribute directly for both get
    and set, until it needs to do something special in which case use
    property().

    The reason why people fill their code up with boiler plate get/set
    methods is to give them the flexibility to change the implementation
    without having to change any of the users. In python you just swap
    from direct attribute access to using property().

    Also note that with property() you can make an attribute read only (by
    defining only the get method) which is often the encapsulation you
    really want - and that is something you can't do in C++.

    --
    Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick
  • Dan Sommers at Feb 28, 2005 at 8:50 pm

    On 28 Feb 2005 10:30:03 GMT, Nick Craig-Wood wrote:

    Actually I would say just access the attribute directly for both get
    and set, until it needs to do something special in which case use
    property().
    The reason why people fill their code up with boiler plate get/set
    methods is to give them the flexibility to change the implementation
    without having to change any of the users. In python you just swap
    from direct attribute access to using property().
    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.

    I usually aim for this: if users of the public interface of my class
    can figure out that I changed the implementation, then I've exposed too
    much. Sure there are exceptions, but that's my basic thought process.

    Sorry about the rant.

    Regards,
    Dan

    --
    Dan Sommers
    <http://www.tombstonezero.net/dan/>
    ?? ? ?? ? c? = 1
  • Andrew Dalke at Feb 28, 2005 at 11:08 pm

    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?

    Andrew
    dalke at dalkescientific.com
  • Dan Sommers at Feb 28, 2005 at 11:49 pm

    On Mon, 28 Feb 2005 23:08:04 GMT, Andrew Dalke 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
  • Thomas Lotze at Mar 1, 2005 at 12:39 am

    Dan Sommers wrote:

    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.
    But then you put application logic into a library function. Doing this
    consistently leads to a monster of a library that tries to account for all
    possible applications. Where does this leave the KISS principle?
    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.
    Then you also avoid lists, dicts and, ironically, methods. Accessing
    methods means to access a callable attribute, after all, with all the
    stuff going on behind the scenes on attribute access.

    --
    Thomas
  • Dan Sommers at Mar 1, 2005 at 2:01 am

    On Tue, 01 Mar 2005 01:39:13 +0100, Thomas Lotze wrote:

    Dan Sommers wrote:
    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.
    But then you put application logic into a library function. Doing this
    consistently leads to a monster of a library that tries to account for
    all possible applications. Where does this leave the KISS principle?
    Maybe I'm "old school," but I usually end up with lots of layers in
    between library functions and application logic. If I think my
    "library" layer is too big, yes, I will add another layer of abstraction
    around it. Nothing says that my application has to talk directly to
    every low-level library function.
    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.
    Then you also avoid lists, dicts and, ironically, methods. Accessing
    methods means to access a callable attribute, after all, with all the
    stuff going on behind the scenes on attribute access.
    By that logic, I'd also avoid Python, which, obviously, I'm don't.

    When I see a simple construct like "a = b," or "a = b[ 2 ]," or even
    "a.b.c = d.e.f," I would like to think that nothing "magic" (for some
    suitable definition of "magic") is happening. Yes, in a language like
    Python, a lot more is happening (and a whole lot more *could* happen)
    under the hood than in the extremely roughly equivalent "move.l d1,d2"
    in assembly language.

    I guess we all have our own personal tolerances for "Explicit is better
    than implicit."

    Regards,
    Dan

    --
    Dan Sommers
    <http://www.tombstonezero.net/dan/>
    ?? ? ?? ? c? = 1
  • Andrew Dalke at Mar 1, 2005 at 2:27 am

    Me:
    What's wrong with the use of attributes in this case and how
    would you write your interface?
    Dan Sommers:
    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.
    Hmmm. I wonder if this is mostly a question of how the
    process decomposition occurs. I think in objects ("thingys
    with state") whereas you think in tasks ("thingys that do stuff")?
    I say that somewhat surprisingly in that I'm not a deep OO
    person - functions are fine with me and I don't like the
    Java/Ruby "everything is in a class" world view.
    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).
    In the case I'm hypothesizing (haven't worked with a temperature
    controller in about 15 years) it's hard to put a layer above
    everything because there could be so many different protocols
    (chemical protocols, not I/O ones) with different rates. Eg,
    it could be an exponential decay, or step-wise approximation
    thereof.

    The note about errors is interesting. For example, if the
    cable to the controller was disconnected then someone, especially
    someone used to memory lookups for attributes, might not expect

    temp_controller.current

    to possibly raise an I/O error exception. On the other hand,
    at the C level that could be memory mapped I/O, so that

    int x = temp_controller.current;

    could also have all sorts of side effects. That case
    is dangerous in C because of its poor exception mechanism.
    I think in Python it's much less of a problem.

    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 )
    Your "tell_the_device_to_change" is my "self.target" and your
    "read_the_temperature_from_the_device" is "self.current_temperature".
    In some sense it comes down to style.

    BTW, had I done this for real I would have two layers, one
    which is communications oriented ("send 'get current temperature'
    message to device") and my object model which uses the messaging
    interface underneath.
    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.
    To give a more recent example for me, which I covered here some
    years back, I wrote an OO interface to an "OO-ish" C library
    for doing chemistry. In the data model, atoms have an atomic
    symbol, a charge and a list of bonds (and many other things).
    Bonds have a bond type and the two atoms at the ends of the bonds
    (and many other things).

    I liked being able to say:

    print atom.symbol, "with charge", atom.charge, "has", \
    len(atom.bonds), "bonds"

    for i, bond in enumerate(bonds):
    print "bond", i, "has type", bond.bondtype

    To me this is a very natural way of querying the data and
    traversing the data structure.

    Now underneath the covers it looks like this:

    atom.charge fails so use __getattr__(atom, "charge")
    __getattr__ uses a dispatch table to get the underlying C function
    which is "dt_getcharge"
    return dt_getcharge(self.handle)

    where "handle" is the handle used by the C library.

    I figured though that this example might be more esoteric
    than my PID controller example, though in retrospect it
    looks like it might be a better justification.

    Andrew
    dalke at dalkescientific.com
  • Dan Sommers at Mar 1, 2005 at 3:18 am

    On Tue, 01 Mar 2005 02:27:03 GMT, Andrew Dalke wrote:

    Me:
    What's wrong with the use of attributes in this case and how
    would you write your interface?
    Dan Sommers:
    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.
    Hmmm. I wonder if this is mostly a question of how the process
    decomposition occurs. I think in objects ("thingys with state")
    whereas you think in tasks ("thingys that do stuff")? I say that
    somewhat surprisingly in that I'm not a deep OO person - functions are
    fine with me and I don't like the Java/Ruby "everything is in a class"
    world view.
    I'm not an OO guy, either. Somewhere back in the mid 90's, I was
    dragged, kicking and screaming, into OO from the world of Structured
    Programming.

    You're right about my notion of an object: I think that if all you have
    is state information, then you just have a C struct and there's no point
    in doing OO. I still write plenty of (smallish) programs like that.
    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).
    In the case I'm hypothesizing (haven't worked with a temperature
    controller in about 15 years) it's hard to put a layer above
    everything because there could be so many different protocols
    (chemical protocols, not I/O ones) with different rates. Eg, it could
    be an exponential decay, or step-wise approximation thereof.
    Yes, it would be difficult (and silly and a maintentance nightmare,
    too!) to put every protocol into the temerature controller. I think at
    that point, I'd put the protocols in a separate "layer," and I'd have to
    think carefully about that layer's interface to the temperature
    controller. My application would be that much farther from even having
    to know the current temperature, let alone access it directly from the
    TemperatureController object (although at some point, the application
    would probably end up displaying that current temperature, so it's not
    like everything is completely isolated from everything else).
    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 )
    Your "tell_the_device_to_change" is my "self.target" and your
    "read_the_temperature_from_the_device" is "self.current_temperature".
    In some sense it comes down to style.
    My point was mostly that change_temerature_to would be a method of a
    TemperatureController object. "tell_the_device_to_change" is whatever
    method/function you have behind setting self.target. As you noted, I
    think of the temperature controller as being able to manage its own
    temperature rather than be a (thin) wrapper around a device driver.
    BTW, had I done this for real I would have two layers, one which is
    communications oriented ("send 'get current temperature' message to
    device") and my object model which uses the messaging interface
    underneath.
    That sounds about right.
    I liked being able to say:
    print atom.symbol, "with charge", atom.charge, "has", \
    len(atom.bonds), "bonds"
    for i, bond in enumerate(bonds):
    print "bond", i, "has type", bond.bondtype
    To me this is a very natural way of querying the data and
    traversing the data structure.
    Now underneath the covers it looks like this:
    atom.charge fails so use __getattr__(atom, "charge")
    __getattr__ uses a dispatch table to get the underlying C function
    which is "dt_getcharge"
    return dt_getcharge(self.handle)
    where "handle" is the handle used by the C library.
    I figured though that this example might be more esoteric
    than my PID controller example, though in retrospect it
    looks like it might be a better justification.
    I like that kind of abstraction: the atom object hides the fact that
    the charge comes out of another layer/library/object entirely.

    Regards,
    Dan

    --
    Dan Sommers
    <http://www.tombstonezero.net/dan/>
    ?? ? ?? ? c? = 1
  • Steve Holden at Mar 1, 2005 at 10:37 am

    Andrew Dalke wrote:
    Me:
    What's wrong with the use of attributes in this case and how
    would you write your interface?

    Dan Sommers:
    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.
    [...]
    Your "tell_the_device_to_change" is my "self.target" and your
    "read_the_temperature_from_the_device" is "self.current_temperature".
    In some sense it comes down to style.
    Indeed, but it also comes down to control paradigm. I don't *know*, but
    I'll make a guess that Dan, who admits to being "old school", hasn't
    done a lot of work with GUIs, which are inherently event-based.

    The difference between your approaches to controlling an external
    process appear to me to be very similar to the differences between the
    traditional "we ask the questions" approach of a batch program (where
    the program logic dictates the sequence of inputs) and the "what just
    happened" approach required by event-driven GUI-based programming.
    BTW, had I done this for real I would have two layers, one
    which is communications oriented ("send 'get current temperature'
    message to device") and my object model which uses the messaging
    interface underneath.

    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.
    Well, you are clearly more up-to-date on Pascal than me, and I blush to
    recall that I used to *teach* the language (back when "structured
    programming" was supposed to be a novelty).
    To give a more recent example for me, which I covered here some
    years back, I wrote an OO interface to an "OO-ish" C library
    for doing chemistry. In the data model, atoms have an atomic
    symbol, a charge and a list of bonds (and many other things).
    Bonds have a bond type and the two atoms at the ends of the bonds
    (and many other things).

    I liked being able to say:

    print atom.symbol, "with charge", atom.charge, "has", \
    len(atom.bonds), "bonds"

    for i, bond in enumerate(bonds):
    print "bond", i, "has type", bond.bondtype

    To me this is a very natural way of querying the data and
    traversing the data structure.

    Now underneath the covers it looks like this:

    atom.charge fails so use __getattr__(atom, "charge")
    __getattr__ uses a dispatch table to get the underlying C function
    which is "dt_getcharge"
    return dt_getcharge(self.handle)

    where "handle" is the handle used by the C library.

    I figured though that this example might be more esoteric
    than my PID controller example, though in retrospect it
    looks like it might be a better justification.
    What this may boil down to is exactly Dan's suggestion that we are all
    comfortable with our own definition of "explicit".

    Really, of course, the only things you need to make explicit are the
    ones that readers don't understand :-)

    so-you-are-fine-if-there's-only-one-reader-ly y'rs - steve
  • Dan Sommers at Mar 1, 2005 at 12:34 pm

    On Tue, 01 Mar 2005 05:37:44 -0500, Steve Holden wrote:

    Indeed, but it also comes down to control paradigm. I don't *know*,
    but I'll make a guess that Dan, who admits to being "old school",
    hasn't done a lot of work with GUIs, which are inherently event-based.
    Not a lot of GUIs, but a lot with (very large, very complex, multi
    tasking, multi processor) event-driven embedded stuff, almost all of
    which was in C and/or assembly languages. The C++ stuff I saw made me
    want to gouge my eyes out, but a lot of us felt that way at the time,
    and we think it came down to the particular (ab)uses of C++ involved.
    Really, of course, the only things you need to make explicit are the
    ones that readers don't understand :-)
    +1 QOTW

    We used to have holy wars over the appropriate level of comments in
    source code.

    Regards,
    Dan

    --
    Dan Sommers
    <http://www.tombstonezero.net/dan/>
    ?? ? ?? ? c? = 1
  • Nick Craig-Wood at Mar 1, 2005 at 5:30 pm

    Dan Sommers wrote:
    We used to have holy wars over the appropriate level of comments in
    source code.
    Well according to the refactoring book I just read (by Martin Fowler)
    the appropriate level of comments is None. If you see a comment you
    should extract the complicated code into a method with a useful name,
    or add well named intermediate variables, or add an assertion.

    Its a point of view... Not 100% sure I agree with it but I see where
    he is coming from. I like a doc-string per public method so pydoc
    looks nice myself...

    --
    Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick
  • Nick Craig-Wood at Mar 1, 2005 at 10:30 am

    Dan Sommers wrote:
    On 28 Feb 2005 10:30:03 GMT,
    Nick Craig-Wood wrote:
    Actually I would say just access the attribute directly for both get
    and set, until it needs to do something special in which case use
    property().
    The reason why people fill their code up with boiler plate get/set
    methods is to give them the flexibility to change the implementation
    without having to change any of the users. In python you just swap
    from direct attribute access to using property().
    The reason their code is so inflexible is that they've filled their
    classes with boiler plate get/set methods.
    Amen to that! As programmers we abhor code duplication, and boiler
    plate is just code duplication. Even if your fancy editor adds it for
    you ;-)
    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.
    I would say this is an excellent philosphy for C++ or Java. When I'm
    writing C++ I try to keep the attributes private. I try not to make
    accessor methods at all until absolutely necessary. I always think
    I've failed if I end up writing getBlah and setBlah methods. In C++
    its always in the back of my mind that an inline accessor method will
    get optimised into exactly the same code as accessing the attribute
    directly anyway.
    I usually aim for this: if users of the public interface of my class
    can figure out that I changed the implementation, then I've exposed too
    much. Sure there are exceptions, but that's my basic thought process.
    However in python, there is no harm in accessing the attributes
    directly. You can change the implementation whenever you like, and
    change the attributes into property()s and the users will never know.

    And, as another poster pointed out - you are already accessing the
    instance variables just by calling its methods, so you shouldn't feel
    too squeamish!

    Read only attributes are easy to understand, unlikely to go wrong and
    faster than getBlah() accessor methods.

    Writable attributes I think are good candidates for methods though.
    Looking inside an object is one thing but changing its internal state
    is another and should probably be done through a defined interface.
    Sorry about the rant.
    I wouldn't call that a rant, it was quite polite compared to some of
    the threads on c.l.p recently ;-)

    --
    Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick
  • Dan Sommers at Mar 1, 2005 at 12:37 pm

    On 01 Mar 2005 10:30:01 GMT, Nick Craig-Wood wrote:

    However in python, there is no harm in accessing the attributes
    directly. You can change the implementation whenever you like, and
    change the attributes into property()s and the users will never know. [ ... ]
    Read only attributes are easy to understand, unlikely to go wrong and
    faster than getBlah() accessor methods.
    Writable attributes I think are good candidates for methods though.
    Looking inside an object is one thing but changing its internal state
    is another and should probably be done through a defined interface.
    I wish I'd said it that well in the first place myself. :-)

    Regards,
    Dan

    --
    Dan Sommers
    <http://www.tombstonezero.net/dan/>
    ?? ? ?? ? c? = 1
  • Carl Banks at Feb 28, 2005 at 10:53 pm

    mirandacascade at yahoo.com wrote:
    When I look at how classes are set up in other languages (e.g. C++), I
    often observe the following patterns:
    1) for each data member, the class will have an accessor member
    function (a Get<whatever> function)
    2) for each data member, the class will have a mutator member function
    (a Set<whatver> function)
    3) data members are never referenced directly; they are always
    referenced with the accessor and mutator functions

    My questions are:
    a) Are the three things above considered pythonic?
    No. It's not good programming practice in C++, either.

    If you have a class that's nothing but a big data structure, you ought
    to use it as a data structure. Writing accessor and mutator methods
    for its fields is just doing a lot of work to accomplish nothing.

    If you want to provide access to a certain occasional field, but you're
    concerned about keeping the interface backwards-compatible, go ahead
    and use them. But try to observe the following rules of thumb:

    1. Don't provide accessor or mutator function to every single member of
    every single class you write. Only provide accessor/mutator functions
    if the accessor/mutator methods are a sensible and useful part of the
    class's interface.

    2. Don't think of these methods as accessors or mutators. Instead,
    think
    of them as methods that access or mutate a certain abstract property of
    the object that happens to be represented by a single member.

    And, keep in mind that, since Python doesn't really have private data,
    you don't have to worry about adding these functions to make debugging
    easier.

    b) What are the tradeoffs of using getattr() and setattr() rather than
    creating accessor and mutator functions for each data member?
    Don't use getattr and setattr unless you have to construct the name of
    the attribute at run time. That's what they're for.


    --
    CARL BANKS
  • Steve Holden at Mar 1, 2005 at 10:43 am

    Carl Banks wrote:
    mirandacascade at yahoo.com wrote:
    [...]
    My questions are:
    a) Are the three things above considered pythonic?

    No. It's not good programming practice in C++, either.

    If you have a class that's nothing but a big data structure, you ought
    to use it as a data structure. Writing accessor and mutator methods
    for its fields is just doing a lot of work to accomplish nothing.
    Unfortunately Java has introduced this as a standard practice, and a lot
    of people who learned their programming by learning Java in the last ten
    years have absolutely no clue what a data structure *is*. (i.e. data,
    with a structure, but no logic required).
    If you want to provide access to a certain occasional field, but you're
    concerned about keeping the interface backwards-compatible, go ahead
    and use them. But try to observe the following rules of thumb:

    1. Don't provide accessor or mutator function to every single member of
    every single class you write. Only provide accessor/mutator functions
    if the accessor/mutator methods are a sensible and useful part of the
    class's interface.

    2. Don't think of these methods as accessors or mutators. Instead,
    think
    of them as methods that access or mutate a certain abstract property of
    the object that happens to be represented by a single member.

    And, keep in mind that, since Python doesn't really have private data,
    you don't have to worry about adding these functions to make debugging
    easier.


    b) What are the tradeoffs of using getattr() and setattr() rather
    than creating accessor and mutator functions for each data member?

    Don't use getattr and setattr unless you have to construct the name of
    the attribute at run time. That's what they're for.
    Well, they are surely helpful in delegation contexts as well, or do I
    misunderstand?

    regards
    Steve
  • Carl Banks at Mar 1, 2005 at 5:32 pm

    Steve Holden wrote:
    Carl Banks wrote:
    Don't use getattr and setattr unless you have to construct the name
    of
    the attribute at run time. That's what they're for.
    Well, they are surely helpful in delegation contexts as well, or do I
    misunderstand?
    I consider that a degenerate form of constructing a name at run time.
    :)

    You're right: I should have said, "Don't use them unless you don't know
    the name at programming time."


    --
    CARL BANKS

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedFeb 25, '05 at 8:01a
activeMar 1, '05 at 5:32p
posts23
users11
websitepython.org

People

Translate

site design / logo © 2022 Grokbase