Speed up properties?!

D

Dr. Peer Griebel

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

Peer
 
P

Peter Otten

Dr. Peer Griebel said:
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
 
C

Christos TZOTZIOY Georgiou

[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(attrgetter("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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,197
Messages
2,571,040
Members
47,635
Latest member
SkyePurves

Latest Threads

Top