Arthur wrote: >>What beyond sugar for leaving off a "()" when trying to retrieve a value >>from a method are we accomplishing by using properties? I have tended to >>look at properties mostly an accommodation to those coming from other >>languages which have something similar, but never as something that was >>core >>to Python or a Pythonic approach to things. Am I missing something >>fundamental? > > > The searching I do on this point only confirms to me that my own confusion > is well shared - perhaps indicating this to be an area not totally OT for > this forum. > > Ray Hettinger's "How-To Guide for Descriptors" > > http://users.rcn.com/python/download/Descriptor.htm > > covers properties, but the use case given is extremely unsatisfying - > essentially offering a situation where a fundamental design change has been > made to a program in mid-stream, and since properties were used in the > initial design, the change can be made with little refactoring.
I'd propose two reasons why properties are so successful. The first explanation comes from eXtreme Programming. One big goal of XP is to stop wasting time doing "big design up front." I've spent enough time in companies where long design meetings (months) produced huge design documents. The documents themselves had a tendency to look like everything was nailed down, while not really answering a lot of questions that had to be solved when writing the code. The length of time spent producing the document, and the general unavailability of the group that wrote it (they typically moved into other committees to write other design documents), led to an increasingly rigid design that reflected neither discoveries or innovations from the coders nor changes in requirements (or at least our understanding of those requirements). XP can be seen as a reaction to that problem. The second explanation is much lower level. In O-O code, there is a distinction between interface and implementation. Essentially, the interface to an object is how the object behaves from a user of that object's point of view. The implementation is how that object accomplishes its behavior. When you separate these concerns, you can more likely keep a programs complexity (in the sense of debugging/ extending) from growing exponentially with the number of lines of code. Properties let you to hide the trade-off between accessing a stored value and computing it on the fly. Without properties, the interface to classes that want to reserve the access/calculate tradeoff must use the Java-like "getVar" functions to fetch any values that might be calculated. > What would it take to create a @property decorator that allows one > to set as well as get? Would we want to? def writeprop(viewvar): '''decorator makes a property from access and a write method''' def view(self): return getattr(self, viewvar) def buildprop(writemethod): return property(view, writemethod) return buildprop Triangle as an example: import math class BaseTriangle(object): @classmethod def check(klass, a, b, c): '''Check three lengths for suitability as triangle sides''' if a >= b + c: raise ValueError, 'Too long: %s >= %s + %s' % (a, b, c) if a <= abs(b - c): raise ValueError, 'Too short: %s <= abs(%s - %s)' % (a, b,c) def __init__(self, a, b, c): self.check(a, b, c) self._a = a self._b = b self._c = c self._reset() def __repr__(self): return '%s(%s, %s, %s)' % (self.__class__.__name__, self.a, self.b, self.c) def _reset(self): '''Called whenever the sides of the triangle change''' pass @writeprop('_a') def a(self, v): self.check(v, self.b + self.c) self._a = v self._reset() @writeprop('_b') def b(self, v): self.check(v, self.a, self.c) self._b = v self._reset() @writeprop('_c') def c(self, v): self.check(v, self.a, self.b) self._c = v self._reset() # One kind of triangle with angles: class Triangle(BaseTriangle): @property def perimeter(self): return self.a + self.b + self.c @property def area(self): "Heron's Formula" s = 0.5 * self.perimeter return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c)) @property def A(self): return math.acos((-self.a**2 + self.b**2 + self.c**2) / (2.0 * self.b * self.c)) @property def B(self): return math.acos((self.a**2 - self.b**2 + self.c**2) / (2.0 * self.a * self.c)) @property def C(self): return math.acos((self.a**2 + self.b**2 - self.c**2) / (2.0 * self.a * self.b)) # Another kind of triangle with angles: class Triangle2(BaseTriangle): def _reset(self): self.perimeter = self.a + self.b + self.c s = 0.5 * self.perimeter self.area = math.sqrt(s * (s - self.a) *(s - self.b) * (s - self.c)) self.A = math.acos((-self.a**2 + self.b**2 + self.c**2) / (2.0 * self.b * self.c)) self.B = math.acos((self.a**2 - self.b**2 + self.c**2) / (2.0 * self.a * self.c)) self.C = math.acos((self.a**2 + self.b**2 - self.c**2) / (2.0 * self.a * self.b)) --Scott David Daniels [EMAIL PROTECTED] _______________________________________________ Edu-sig mailing list [EMAIL PROTECTED] http://mail.python.org/mailman/listinfo/edu-sig