This topic is about the OO style employed by Webware. It is a long 
topic and some may find it boring, but it affects the programmatic 
interface to Webware, so I felt it should be posted to -discuss rather 
than -devel for all to see.

Here is the main point:

With the advent of Python 2.2, we have the "properties style" as 
described here:
http://www.python.org/2.2/descrintro.html#property

  Should Webware adopt the "properties style"?

+ Easy to read and write.
+ Would make Webware source more Pythonic.
+ Preserves "opaqueness".
+ As fast as mixed style and faster than other styles.
- Existing code bases would require updates.
- Would required Python 2.2 OR that we provide the GetterSetter helper 
for 2.0 and 2.1 users (with the understanding that performance might 
take a dive for such users).


And here is a detailed background if you care to read further:

When writing classes, the "mixed style" is to use both data attributes 
and methods to access values:

# Vector.py
class Vector:
        def __init__(self):
                self.x = self.y = 0
        def length(self):
                return math.sqrt(self.x*self.x + self.y*self.y)

# prog.py
v = Vector()
v.x = 1
v.y = 4
print v.length()

I don't like the mixed style because if you switch a "foo" from a 
method to an attribute or the other way around, you break the interface:

class Vector:
        def __init__(self):
                self.x = self.y = 0
        def setX(self, x):
                self.x = x
                self._computerLength()
        def setY(self, y):
                self.y = y
                self._computeLength()
        def _computeLength(self):
                self.length = math.sqrt(self.x*self.x + self.y*self.y)

Now prog.py is broken simply because we wanted to compute the length 
when X or Y are set (presumably we have determined it is asked for much 
more frequently than it is altered). Setting X and Y broke because they 
have to be methods now and asking for the length broke because it no 
longer requires paren()s.

(Note: These code examples are neither perfect, nor tested. They are 
just to illustrate the issues.)

Some people solve this by using the "getter-setter style":

# GetterSetter.py
class GetterSetter:

        def __getattr__(self, name):
                if not name.startswith('__'):
                        method = getattr(self, 'get_' + name, None)
                        if method:
                                return method()
                raise AttributeError, name

        def __setattr__(self, name, value):
                if not name.startswith('__'):
                        method = getattr(self, 'set_' + name, None)
                        if method:
                                method(value)
                self.__dict__[name] = value

# Vector.py
class Vector(GetterSetter):

        def __init__(self):
                self.x = self.y = 0

        def set_x(self, value):
                self.__dict__['x'] = value
                # ^^ use self.__dict__ to avoid infinite recursion to __setattr__
                self._computeLength()

        def set_y(self, value):
                self.__dict__['y'] = value
                self._computeLength()

        def _computeLength(self):
                self.length = math.sqrt(self.x*self.x + self.y*self.y)

Pros and cons of getter-setter style:
+ Opaque: No code using Vector is broken.
+ Concise: Vector users can conveniently avoid the extra parens and 
"set" words and such that come with methods. eg. v.x = 5 and v.length 
instead of v.setX(5) and v.length()
- Performance: Having experimented with this style in a recent project, 
I found it could be a major source of slow down. Particularly, 
__setattr__ adds a method call and extra Python byte code to every 
attribute assignment. My program slowed down by at least 10X.
- Implementation: The use of self.__dict__['foo'] is ugly and 
forgetting it results in infinite recursion (quickly spotted of course).
- Implementation: __getattr__ and __setattr__ are "asymmetric" in their 
design. The first is called as a last resort, the other is always 
called. This leads to some subtle issues in how you treat your 
attributes.


Next we have the "encapsulation with methods" style which I guess I 
took from Smalltalk & Objective-C and is the current Webware style. Use 
methods for everything large and small. Pros and cons:
+ No code breaks due to simple interface changes.
+ Faster execution than the getter-setter style.
+ Generally encourages more protection of the object's data attributes.
+ Easy to understand
- Slower execution than the mixed style.
- More typing: obj.setFoo()  obj.foo()   self._foo


In a recent, private project I started with the getter-setter style and 
found it more convenient than method encapsulation, but too expensive 
performance-wise. I then scaled back to the mixed style, but with the 
problems described above. Overall, I still liked the conciseness of 
both styles. I felt like coding was quicker and just as readable.

The properties style seems to give all the pros and only legacy-related 
cons. See the beginning of the message.


Reactions?

-Chuck

_______________________________________________
Webware-discuss mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/webware-discuss

Reply via email to