Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and how often are properties calculated in python? [duplicate]

Tags:

python

Possible Duplicate:
python: are property fields being cached automatically?

As a concern about effeciency of properties in python, I was wondering when and how often they are called.

To use a simple example, say I subclass namedtuple and I have something like:

from collections import namedtuple
from math import pi

class Circle (namedtuple('Circle', 'x, y, r')):
    __slots__ = ()

    @property
    def area(self):
        return pi*self.r**2

unitCircle = Circle(0, 0, 1.0)
print 'The area of the unit circle is {0} units'.format(unitCircle.area)

I assume that area is not calculated until the first time it is called, but once it is called, is that value cached until something changes or is it recalculated every time it is called?

Put another way, if I have a property that (unlike this one) is relatively expensive to calculate and will be used repeatedly, should I let it be a property, or is it more effecient to store it as a value and explicitly caclulate it when it really needs to be updated?

like image 984
TimothyAWiseman Avatar asked Sep 06 '12 20:09

TimothyAWiseman


2 Answers

Decorators in python (like @property) get evaluated when the class is loaded. Sometimes the resulting effects on the class will include extra functions, but the decorator itself is only run once.

like image 27
desimusxvii Avatar answered Nov 02 '22 23:11

desimusxvii


Properties are not cached unless you do it explicitly, so the code is run every time the property is accessed. Try:

@property
def area(self):
    try:
        return self._area
    except AttributeError:
        area = pi*self.r**2
        self._area = area
        return area

If you want to be able to recalculate the value on demand occasionally, do something like:

@property
def area(self):
    try:
        return self._area
    except AttributeError:
        self.recalc_area()
        return self._area

def recalc_area(self):
    self._area = pi*self.r**2

Or, if you want to do it more automatically:

@property
def area(self):
    try:
        return self._area
    except AttributeError:
        area = pi*self.radius**2
        self._area = area
        return area

@property
def radius(self):
    return self._radius

@radius.setter
def radius(self, radius):
    try:
        del self._area
    except AttributeError:
        pass
    self._radius = radius
like image 101
Silas Ray Avatar answered Nov 03 '22 00:11

Silas Ray