
ethan at stoneleaf
Nov 25, 2009, 7:47 AM
Post #10 of 12
(355 views)
Permalink
|
|
Re: attributes, properties, and accessors -- philosophy
[In reply to]
|
|
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~ -- http://mail.python.org/mailman/listinfo/python-list
|