attributes, properties, and accessors -- philosophy
Ethan Furman
ethan at stoneleaf.us
Wed Nov 25 10:47:39 EST 2009
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~
More information about the Python-list
mailing list