Getters and Setters

Tim Peters tim_one at email.msn.com
Thu Jul 15 04:09:57 EDT 1999


[Neil Schemenauer]
> Recently I found myself wishing that Python had automatic getters
> and setters like CLOS.

Bleech.

> For those who are not familiar, CLOS (and Dylan) create a "getter"
> and "setter" method for each attribute of a class. This saves the
> programmer from writing "getX" and "setX" for every attribute when
> no special action is needed.  Later, an explict method can be created
> if needed.

Python goes one better:  you can write an explicit method if needed, but it
doesn't encourage bad practice by automatically supplying methods that
expose every data attribute, crying "use me! abuse me!" <wink>.

> An implementation of this idea is attached.  With this
> implementation, these automatic methods seem to be about 8 times
> slower than explicit methods.

And some later corrected code boosted the factor to 10.

> Maybe Tim and friends can do something about that.  I would appreciate
> any comments.

I'll attach code that gets to the same end, but where the automatic methods
actually run faster than explicit ones.  I won't say why, though <wink --
but you'll figure it out>.

General comments:

+ Don't think OO so much as functional for this kind of thing.  OO just adds
overhead to what should be a very straightforward task.  Put on your Lisp
hat here!

+ time.clock is preferred for benchmarking.

+ Don't count the time it takes to generate range(n).

+ Don't count the time it takes to start a print.

> On a related note, has anyone considered adding hygenic macros to
> Python?

No.  People have *suggested* it, but those who have never showed any sign of
*doing* something about it <wink>.

> Due to the high cost of function calls in Python they would probably
> be a useful (and for other things too).  I have the feeling that hygenic
> macros are much easier to do in a language like Lisp.

No question about that one!  Python program fragments aren't sexps, they're
strings, and for starters there's no clear way to expose their internal
structure.

> Maybe Dylan can give us some ideas.

For one, that it's very much easier and clearer in a language with
relentlessly uniform syntax -- like Lisp <0.1 wink>.

all-that-glitters-is-not-sputum-ly y'rs  - tim


Oops!  Almost forgot the code!  Dump _Getter.  Dump _Setter.  Have the mixin
class build the obvious function for what you're after, and add that
directly to self as an attribute.  Then there's no mixin overhead at all
after the first time a set/get method is invoked for an instance.  Downside:
generates many function objects.  Possible alternative:  plug synthesized
get/set functions into the class object instead; a little slower, but less
proliferation of function objects.

class GetterSetter:
    def __getattr__(self, name):
        if name[:3] == "get":
            def getter(d=self.__dict__, key=name[3:]):
                return d[key]
            setattr(self, name, getter)
            return getter

        elif name[:3] == "set":
            def setter(value, d=self.__dict__, key=name[3:]):
                d[key] = value
            setattr(self, name, setter)
            return setter

        else:
            raise AttributeError(name)

def test():
    import time
    class A(GetterSetter):
        def __init__(self):
            self.X = self.Y = 1
        def getY(self):
            return self.Y
        def setY(self, v):
            self.Y = v
    a = A()
    n = 1000
    indices = range(n)
    print 'Comparing', n, 'iterations'
    start = time.clock()
    for x in indices:
        a.getX()
        a.setX(x)
    finish = time.clock()
    print 'GetterSetter', finish - start
    start = time.clock()
    for x in indices:
        a.getY()
        a.setY(x)
    finish = time.clock()
    print 'explicit function', finish - start

if __name__ == '__main__':
    test()






More information about the Python-list mailing list