Speed up properties?!

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dr. Peer Griebel

    Speed up properties?!

    Hi,

    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__=='__ma in__':
    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?

    Peer




  • Peter Otten

    #2
    Re: Speed up properties?!

    Dr. Peer Griebel wrote:
    [color=blue]
    > 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__=='__ma in__':
    > 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?[/color]

    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


    Comment

    • Christos TZOTZIOY Georgiou

      #3
      Re: Speed up properties?!

      On Fri, 14 May 2004 08:53:30 +0200, in comp.lang.pytho n Peter Otten
      wrote:

      [comparing direct attribute access and indirect through property get]

      A slight addition to your code for another alternative (2.4 only) of
      property gets (the z property):

      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)

      from operator import attrgetter
      z = property(attrge tter("x"))

      o = C()

      yields (on my laptop):

      C:\Temp>timeit -s "from propspeed import o" o.x
      1000000 loops, best of 3: 0.655 usec per loop

      C:\Temp>timeit -s "from propspeed import o" o.y
      100000 loops, best of 3: 2.36 usec per loop

      C:\Temp>timeit -s "from propspeed import o" o.z
      1000000 loops, best of 3: 1.51 usec per loop
      --
      TZOTZIOY, I speak England very best,
      Ils sont fous ces Redmontains! --Harddix

      Comment

      Working...