Performance penalty for using properties?

Peter Otten __peter__ at web.de
Sun Mar 14 09:27:00 CET 2004


Robert Brewer wrote:

> Peter Otten wrote:
>> Kenneth McDonald wrote:
>> 
>> > Now that I'm back to Python and all the new (to me) cool features,
>> > I find I'm using properties a lot, i.e. I'm defining:
>> > 
>> > foo = property(fset=..., fget=...)
>> > 
>> > for a number of properties, in many of my classes. I'm not using
>> > them for anything performance critical yet, but could see myself
>> > doing so in the future. Can anyone comment on the performance
>> > costs associated with properties vs. simple attribute lookup?
>> 
>> It seems I'm becoming obsessed with timeit.py :-)
> 
> ISTR Alex Martelli went through such a phase.. ;)
> 
>> <property.py>
>> class Test(object):
>>     def getvalue(self):
>>         return self._value
>>     value = property(getvalue)
>> 
>> t = Test()
>> t._value = 123
>> </property.py>
>> 
>> $ timeit.py -s"from property import t" "t._value"
>> 1000000 loops, best of 3: 0.207 usec per loop
>> $ timeit.py -s"from property import t" "t.getvalue()"
>> 1000000 loops, best of 3: 0.918 usec per loop
>> $ timeit.py -s"from property import t" "t.value"
>> 1000000 loops, best of 3: 1.03 usec per loop
>> 
>> Roughly factor five, most of the time being consumed by the
>> implied function call.
> 
> I've always used "property" as sugar for when I would otherwise have
> overriden __getattr(ibute)__, in which case the performance is not that
> different.

I can think of other patterns (all untested code). Let's pretend area
calculation were time-costly. Then

class Square:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.area = x*y
    setExtent = __init__

should be less efficient than 

class LazySquare(object):
    # probably bad, don't do it 
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def getarea(self):
        try:
            return self._area
        except Attribute:
            self._area = self.x * self.y
        return self._area
    area = property(getarea)

    def setExtent(self, x, y):
        self.x = x
        self.y = y
        try:
            del self._area
        except AttributeError:
            pass

most of the time. At present all your gains may be lost by the repeated
overhead of the getarea() calls. Another one:

class A(object):
    # probably bad, don't do it
    def getValue(self):
        return self._value
    def setValue(self, newValue):
        if complicatedValidityCheck(newValue):
            self._value = newValue
        else:
            raise ValueError
    value = property(getValue, setValue)

Here bothering client code with explicit setter calls would give significant
speed gains if write access is rare compared with reading.

I think finding a way for properties to access attributes without wrapping
them into a function call would be worth the effort. The penalty for clean
interfaces should be as low as possible.

Peter



More information about the Python-list mailing list