attributes, properties, and accessors -- philosophy

Discussion in 'Python' started by Ethan Furman, Nov 23, 2009.

  1. Ethan Furman

    Ethan Furman Guest

    The problem I have with properties is my typing. I'll end up assigning
    to an attribute, but get the spelling slightly wrong (capitalized, or
    missing an underscore -- non-obvious things when bug-hunting), so now I
    have an extra attribute which of course has zero effect on what I'm
    trying to do and I start getting wierd results like viewing deleted
    records when I *know* I set useDeleted = False... 30 minutes later I
    notice it was /supposed/ to be use_deleted. *sigh*

    So -- to keep myself out of trouble -- I have started coding such things
    as, for example:

    result = table.use_deleted() # returns True or False
    table.use_deleted(False) # skip deleted records

    instead of

    result = table.use_deleted
    table.use_deleted = False

    My question: is this [ severely | mildly | not at all ] un-pythonic?

    ~Ethan~
    Ethan Furman, Nov 23, 2009
    #1
    1. Advertising

  2. Ethan Furman a écrit :
    > The problem I have with properties is my typing. I'll end up assigning
    > to an attribute, but get the spelling slightly wrong (capitalized, or
    > missing an underscore -- non-obvious things when bug-hunting), so now I
    > have an extra attribute which of course has zero effect on what I'm
    > trying to do and I start getting wierd results like viewing deleted
    > records when I *know* I set useDeleted = False... 30 minutes later I
    > notice it was /supposed/ to be use_deleted. *sigh*
    >
    > So -- to keep myself out of trouble -- I have started coding such things
    > as, for example:
    >
    > result = table.use_deleted() # returns True or False
    > table.use_deleted(False) # skip deleted records
    >
    > instead of
    >
    > result = table.use_deleted
    > table.use_deleted = False
    >
    > My question: is this [ severely | mildly | not at all ] un-pythonic?


    Definitly and totally unpythonic. The first solution to your problem is
    to stick to standard naming conventions. If this is not enough, Chris
    pointed you to really useful tools. Also, you can override __setattr__
    to catch such errors - at least during the coding/debug phase.
    Bruno Desthuilliers, Nov 24, 2009
    #2
    1. Advertising

  3. Ethan Furman

    Ethan Furman Guest

    Bruno Desthuilliers wrote:
    > Ethan Furman a écrit :
    >
    >> The problem I have with properties is my typing. I'll end up
    >> assigning to an attribute, but get the spelling slightly wrong
    >> (capitalized, or missing an underscore -- non-obvious things when
    >> bug-hunting), so now I have an extra attribute which of course has
    >> zero effect on what I'm trying to do and I start getting wierd results
    >> like viewing deleted records when I *know* I set useDeleted = False...
    >> 30 minutes later I notice it was /supposed/ to be use_deleted. *sigh*
    >>
    >> So -- to keep myself out of trouble -- I have started coding such
    >> things as, for example:
    >>
    >> result = table.use_deleted() # returns True or False
    >> table.use_deleted(False) # skip deleted records
    >>
    >> instead of
    >>
    >> result = table.use_deleted
    >> table.use_deleted = False
    >>
    >> My question: is this [ severely | mildly | not at all ] un-pythonic?

    >
    >
    > Definitly and totally unpythonic. The first solution to your problem is
    > to stick to standard naming conventions. If this is not enough, Chris
    > pointed you to really useful tools. Also, you can override __setattr__
    > to catch such errors - at least during the coding/debug phase.


    Good tools to know about, and a consistent naming pattern also makes
    life easier (which I have since done ;).

    Let's head towards murkier waters (at least murkier to me -- hopefully
    they can be easily clarified): some of the attributes are read-only,
    such as record count; others are not directly exposed, but still
    settable, such as table version; and still others require a small amount
    of processing... at which point do I switch from simple attribute access
    to method access?

    ~Ethan~
    Ethan Furman, Nov 24, 2009
    #3
  4. Ethan Furman

    Chris Rebert Guest

    On Tue, Nov 24, 2009 at 9:39 AM, Ethan Furman <> wrote:
    > Bruno Desthuilliers wrote:
    >> Ethan Furman a écrit :
    >>> The problem I have with properties is my typing.  I'll end up assigning
    >>> to an attribute, but get the spelling slightly wrong (capitalized, or
    >>> missing an underscore -- non-obvious things when bug-hunting), so now I have
    >>> an extra attribute which of course has zero effect on what I'm trying to do
    >>> and I start getting wierd results like viewing deleted records when I *know*
    >>> I set useDeleted = False... 30 minutes later I notice it was /supposed/ to
    >>> be use_deleted.  *sigh*
    >>>
    >>> So -- to keep myself out of trouble -- I have started coding such things
    >>> as, for example:
    >>>
    >>> result = table.use_deleted()       # returns True or False
    >>> table.use_deleted(False)           # skip deleted records
    >>>
    >>> instead of
    >>>
    >>> result = table.use_deleted
    >>> table.use_deleted = False
    >>>
    >>> My question:  is this [ severely | mildly | not at all ] un-pythonic?

    >>
    >>
    >> Definitly and totally unpythonic. The first solution to your problem is to
    >> stick to standard naming conventions. If this is not enough, Chris pointed
    >> you to really useful tools. Also, you can override __setattr__ to catch such
    >> errors - at least during the coding/debug phase.

    >
    > Good tools to know about, and a consistent naming pattern also makes life
    > easier (which I have since done ;).
    >
    > Let's head towards murkier waters (at least murkier to me -- hopefully they
    > can be easily clarified):  some of the attributes are read-only, such as
    > record count; others are not directly exposed, but still settable, such as
    > table version; and still others require a small amount of processing... at
    > which point do I switch from simple attribute access to method access?


    Thanks to the magic of properties, the end-user-programmer need not
    know which you're using:

    http://docs.python.org/library/functions.html#property

    Cheers,
    Chris
    --
    http://blog.rebertia.com
    Chris Rebert, Nov 24, 2009
    #4
  5. Ethan Furman

    Lie Ryan Guest

    Ethan Furman wrote:
    >
    > Good tools to know about, and a consistent naming pattern also makes
    > life easier (which I have since done ;).
    >
    > Let's head towards murkier waters (at least murkier to me -- hopefully
    > they can be easily clarified): some of the attributes are read-only,
    > such as record count; others are not directly exposed, but still
    > settable, such as table version; and still others require a small amount
    > of processing... at which point do I switch from simple attribute access
    > to method access?
    >
    > ~Ethan~


    method accessor is not pythonic, use property

    property can be read-only, write-only (!), and it can process data
    before returning and setting the real attributes.
    Lie Ryan, Nov 24, 2009
    #5
  6. Ethan Furman

    Ethan Furman Guest

    Chris Rebert wrote:
    > On Tue, Nov 24, 2009 at 9:39 AM, Ethan Furman <> wrote:
    >
    >>Bruno Desthuilliers wrote:
    >>
    >>>Ethan Furman a écrit :
    >>>
    >>>>The problem I have with properties is my typing. I'll end up assigning
    >>>>to an attribute, but get the spelling slightly wrong (capitalized, or
    >>>>missing an underscore -- non-obvious things when bug-hunting), so now I have
    >>>>an extra attribute which of course has zero effect on what I'm trying to do
    >>>>and I start getting wierd results like viewing deleted records when I *know*
    >>>>I set useDeleted = False... 30 minutes later I notice it was /supposed/ to
    >>>>be use_deleted. *sigh*
    >>>>
    >>>>So -- to keep myself out of trouble -- I have started coding such things
    >>>>as, for example:
    >>>>
    >>>>result = table.use_deleted() # returns True or False
    >>>>table.use_deleted(False) # skip deleted records
    >>>>
    >>>>instead of
    >>>>
    >>>>result = table.use_deleted
    >>>>table.use_deleted = False
    >>>>
    >>>>My question: is this [ severely | mildly | not at all ] un-pythonic?
    >>>
    >>>
    >>>Definitly and totally unpythonic. The first solution to your problem is to
    >>>stick to standard naming conventions. If this is not enough, Chris pointed
    >>>you to really useful tools. Also, you can override __setattr__ to catch such
    >>>errors - at least during the coding/debug phase.

    >>
    >>Good tools to know about, and a consistent naming pattern also makes life
    >>easier (which I have since done ;).
    >>
    >>Let's head towards murkier waters (at least murkier to me -- hopefully they
    >>can be easily clarified): some of the attributes are read-only, such as
    >>record count; others are not directly exposed, but still settable, such as
    >>table version; and still others require a small amount of processing... at
    >>which point do I switch from simple attribute access to method access?

    >
    >
    > Thanks to the magic of properties, the end-user-programmer need not
    > know which you're using:
    >
    > http://docs.python.org/library/functions.html#property


    You know, when I first read that bit on properties a while back, the
    explanation of the decorators and how a property was also a decorator
    for the setter and deleter bits completely lost me. Since then I've
    played with decorators a bit, written a configaration module that uses
    them, and just now, reading the description... it was so elegantly
    simple it almost brought tears to my eyes *sniff*. I love Python.

    Okay, I'll go back and switch all my attributes *back* to attributes --
    and properties will be much nicer than my original implementation (using
    __getattr__ and __setattr__).

    Many thanks to all who answered!

    ~Ethan~
    Ethan Furman, Nov 24, 2009
    #6
  7. Ethan Furman a écrit :
    >
    > Let's head towards murkier waters (at least murkier to me -- hopefully
    > they can be easily clarified): some of the attributes are read-only,
    > such as record count; others are not directly exposed, but still
    > settable, such as table version; and still others require a small amount
    > of processing... at which point do I switch from simple attribute access
    > to method access?


    Short answer : you don't !-)

    Long answer : well, in fact you do, but the client code doesn't have to
    be aware that it's in fact calling an accessor.

    Before we go into more details, you have to know that Python has a
    pretty good support for computed attributes, with both a simple generic
    solution (the property type) and the full monty (custom types
    implementing the descriptor protocol). So from the "interface" POV, you
    should never have an explicit accessor method for what is semantically
    an attribute (wheter the attribute is a plain or a computed one being
    part of the implementation).

    Let's start with your second point: "not directly exposed but still
    settable". I assume you mean "not part of the interface, only supposed
    to be accessed (rw) from the methods" - if not, please pardon my
    stupidity and provide better explanations !-). If yes: Python doesn't
    have "language inforced" access restrictions (private / protected /
    etc), but a *very strong* naming convention which is that names starting
    with a leading underscore are implementation details, not part of the
    official interface, and shouldn't be accessed directly. Kind of a
    "warranty voided if unsealed".

    So if you have attributes you don't want to "expose" to the outside
    world, just add a single leading underscore to their names.

    First and third points are solved by using computed attributes - usually
    a property. The property type takes a few accessor functions as
    arguments - typically, a getter and a setter, and eventually a
    "deleter". Used as a class attribute, a property instance will hook up
    into the attribute lookup / setup mechanism (__getattribute__ and
    __setattr__), and will call resp. it's getter or setter function,
    passing it the instance and (for the setter) value.

    This directly solves the third point. For the first one, the obvious
    solution is to use a property with a setter that raises an exception -
    canonically, an AttributeError with a message explaining that the
    attribute is read-only.

    And for something more hands-on:

    class Person(object):
    def __init__(self, firstname, lastname, birthdate):
    self.firstname = firstname
    self.lastname = lastnale
    self.birthdate = birthdate
    self._foo = 42 # implementation only

    def _getfullname(self):
    return "%s %s" % (self.firstname, self.lastname)
    def _setfullname(self, value):
    raise AttributeError("%s.fullname is read-only" % type(self)
    fullname = property(fget=_getfullname, fset=_setfullname)

    def _getage(self):
    return some_computation_with(self.birthdate)
    def _setage(self, value):
    raise AttributeError("%s.age is read-only" % type(self)
    age = property(fget=_getage, fset=_setage)


    For more on computed attributes, you may want to read about the
    "descriptor protocol" (google is your friend as usual). This and the
    attribute resolution mechanism are fundamental parts of Python's inner
    working. Learn how it works if you really want to leverage Python's power.

    HTH
    Bruno Desthuilliers, Nov 25, 2009
    #7
  8. Ethan Furman a écrit :
    (snip)

    > Okay, I'll go back and switch all my attributes *back* to attributes --
    > and properties will be much nicer than my original implementation (using
    > __getattr__ and __setattr__).


    It will also be faster FWIW.
    Bruno Desthuilliers, Nov 25, 2009
    #8
  9. Ethan Furman

    Ethan Furman Guest

    Bruno Desthuilliers wrote:
    > Ethan Furman a écrit :
    >
    >>
    >> Let's head towards murkier waters (at least murkier to me -- hopefully
    >> they can be easily clarified): some of the attributes are read-only,
    >> such as record count; others are not directly exposed, but still
    >> settable, such as table version; and still others require a small
    >> amount of processing... at which point do I switch from simple
    >> attribute access to method access?

    >
    >
    > Short answer : you don't !-)
    >
    > Long answer : well, in fact you do, but the client code doesn't have to
    > be aware that it's in fact calling an accessor.
    >
    > Before we go into more details, you have to know that Python has a
    > pretty good support for computed attributes, with both a simple generic
    > solution (the property type) and the full monty (custom types
    > implementing the descriptor protocol). So from the "interface" POV, you
    > should never have an explicit accessor method for what is semantically
    > an attribute (wheter the attribute is a plain or a computed one being
    > part of the implementation).
    >
    > Let's start with your second point: "not directly exposed but still
    > settable". I assume you mean "not part of the interface, only supposed
    > to be accessed (rw) from the methods" - if not, please pardon my
    > stupidity and provide better explanations !-).


    Better explanation: attribute is publicly available, but buried a couple
    layers deep in a private structure (yes, private structure name starts
    with a leading underscore).

    > If yes: Python doesn't
    > have "language inforced" access restrictions (private / protected /
    > etc), but a *very strong* naming convention which is that names starting
    > with a leading underscore are implementation details, not part of the
    > official interface, and shouldn't be accessed directly. Kind of a
    > "warranty voided if unsealed".
    >
    > So if you have attributes you don't want to "expose" to the outside
    > world, just add a single leading underscore to their names.
    >
    > First and third points are solved by using computed attributes - usually
    > a property. The property type takes a few accessor functions as
    > arguments - typically, a getter and a setter, and eventually a
    > "deleter". Used as a class attribute, a property instance will hook up
    > into the attribute lookup / setup mechanism (__getattribute__ and
    > __setattr__), and will call resp. it's getter or setter function,
    > passing it the instance and (for the setter) value.
    >
    > This directly solves the third point. For the first one, the obvious
    > solution is to use a property with a setter that raises an exception -
    > canonically, an AttributeError with a message explaining that the
    > attribute is read-only.
    >
    > And for something more hands-on:
    >
    > class Person(object):
    > def __init__(self, firstname, lastname, birthdate):
    > self.firstname = firstname
    > self.lastname = lastnale
    > self.birthdate = birthdate
    > self._foo = 42 # implementation only
    >
    > def _getfullname(self):
    > return "%s %s" % (self.firstname, self.lastname)
    > def _setfullname(self, value):
    > raise AttributeError("%s.fullname is read-only" % type(self)
    > fullname = property(fget=_getfullname, fset=_setfullname)
    >
    > def _getage(self):
    > return some_computation_with(self.birthdate)
    > def _setage(self, value):
    > raise AttributeError("%s.age is read-only" % type(self)
    > age = property(fget=_getage, fset=_setage)
    >
    >
    > For more on computed attributes, you may want to read about the
    > "descriptor protocol" (google is your friend as usual). This and the
    > attribute resolution mechanism are fundamental parts of Python's inner
    > working. Learn how it works if you really want to leverage Python's power.
    >
    > HTH


    Very helpful, thank you. Hopefully my brain will be up to the
    descriptor protocol this time... the last couple times were, um, less
    than successful. :)

    ~Ethan~
    Ethan Furman, Nov 25, 2009
    #9
  10. Bruno Desthuilliers, Nov 25, 2009
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Flip
    Replies:
    2
    Views:
    305
  2. Steven T. Hatton

    The real issue with accessors and mutators

    Steven T. Hatton, Nov 9, 2004, in forum: C++
    Replies:
    12
    Views:
    540
    Gary Labowitz
    Nov 10, 2004
  3. Bill
    Replies:
    2
    Views:
    341
    Neil Dunn
    Mar 10, 2006
  4. mystilleef
    Replies:
    116
    Views:
    6,538
    Ed Jensen
    Jul 21, 2006
  5. Sam Samnah

    Composite controls and Property Accessors

    Sam Samnah, Jun 27, 2005, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    111
    Sam Samnah
    Jun 27, 2005
Loading...

Share This Page