Speed up properties?!

Peter Otten __peter__ at web.de
Fri May 14 02:53:30 EDT 2004


Dr. Peer Griebel wrote:

> I have a class with some properties.  I would like to verify that only
> valid values are assigned to the properties using assert.  Therefore I
> code setters and getters and use property() to convert these to have a
> real property.
> 
> Since the verification is only performed in __debug__ runs the
> property() is quite a lot of overhead.  I tried to circumvent it.  This
> is my result so far:
> 
> 
> class C(object):
>      def __init__(self):
>          self._x = 5
>          if not __debug__:
>              self.x = property(self._x, self._x)
> 
>      def getX(self):
>          return self._x
> 
>      def setX(self, v):
>          assert 0 <= v <= 5
>          self._x = v
> 
>      if __debug__:
>          x = property(getX, setX)
> 
> o = C()
> def test():
>      o.x
> 
> if __name__=='__main__':
>      from timeit import Timer
>      t = Timer("test()", "from __main__ import test")
>      print t.timeit()
> 
> 
> 
> As you can see, in non __debug__ runs the accesses of the x property do
> not result in calls to getX or setX.  There I can get a speedup of 2!
> But to be honest: I don't like this aproach. So is there some better,
> cleaner way?

class C(object):
    def __init__(self):
        self.setX(5)

    def setX(self, x):
        if not 0 <= x <= 5:
            raise ValueError
        self.x = x

    # for speed comparison only:
    y = property(lambda s: s.x)

o = C()

With the above, my timings show an even greater speed difference:

$ timeit.py -s'from propspeed import o' 'o.x'
1000000 loops, best of 3: 0.235 usec per loop
$ timeit.py -s'from propspeed import o' 'o.y'
1000000 loops, best of 3: 1.04 usec per loop

Special debug code is dangerous because it can hide errors in the final
version. So, if speed is that important and read access paramount, go for
the asymmetric solution and use o.x for read access and o.setX() - always
checked - for write access. 
However, my guess is that in most cases you will hardly feel any impact on
the overall speed of your program, and in that case I'd recommend an x
property - again with the value check preserved in the non-debug version.
If you then encounter a performance problem, you probably can pin it down to
some inner loop, and replacing o.x with o._x (only) there should be
painless.

Peter





More information about the Python-list mailing list