Recipe 6.8. Avoiding Boilerplate Accessors for PropertiesCredit: Yakov Markovitch ProblemYour classes use some property instances where either the getter or the setter is just boilerplate code to fetch or set an instance attribute. You would prefer to just specify the attribute name, instead of writing boilerplate code. SolutionYou need a factory function that catches the cases in which either the getter or the setter argument is a string, and wraps the appropriate argument into a function, then delegates the rest of the work to Python's built-in property: def xproperty(fget, fset, fdel=None, doc=None): if isinstance(fget, str): attr_name = fget def fget(obj): return getattr(obj, attr_name) elif isinstance(fset, str): attr_name = fset def fset(obj, val): setattr(obj, attr_name, val) else: raise TypeError, 'either fget or fset must be a str' return property(fget, fset, fdel, doc) DiscussionPython's built-in property is very useful, but it presents one minor annoyance (it may be easier to see as an annoyance for programmers with experience in Delphi). It often happens that you want to have both a setter and a "getter", but only one of them actually needs to execute any significant code; the other one simply needs to read or write an instance attribute. In that case, property still requires two functions as its arguments. One of the functions will then be just "boilerplate code" (i.e., repetitious plumbing code that is boring, and often voluminous, and thus a likely home for bugs). For example, consider: class Lower(object): def _ _init_ _(self, s=''): self.s = s def _getS(self): return self._s def _setS(self, s): self._s = s.lower( ) s = property(_getS, _setS) Method _getS is just boilerplate, yet you have to code it because you need to pass it to property. Using this recipe, you can make your code a little bit simpler, without changing the code's meaning: class Lower(object): def _ _init_ _(self, s=''): self.s = s def _setS(self, s): self._s = s.lower( ) s = xproperty('_s', _setS) The simplification doesn't look like much in one small example, but, applied widely all over your code, it can in fact help quite a bit. The implementation of factory function xproperty in this recipe's Solution is rather rigidly coded: it requires you to pass both fget and fset, and exactly one of them must be a string. No use case requires that both be strings; when neither is a string, or when you want to have just one of the two accessors, you can (and should) use the built-in property directly. It is better, therefore, to have xproperty check that it is being used accurately, considering that such checks remove no useful functionality and impose no substantial performance penalty either. See AlsoLibrary Reference and Python in a Nutshell documentation on the built-in property. |