How to use Python properties effectively?

Let's say I have a Foo class that stores some statistics, and I want to encapsulate access to this data using Python properties. This is especially useful, for example, when I save only the variance of a variable and want to have access to its standard deviations: in this case, I could define the Foo.std property and make it return the square root of the variance.

The problem with this approach is that if I need to access Foo.std several times, I will calculate the square root each time; in addition, since the designation of the property exactly matches the designation of the attribute, the user of my class may not know that the calculation occurs each time the property is accessed.

In this example, one alternative would be to calculate the standard deviation each time I update my variance and set it as an attribute. However, this would be inefficient if I did not need to access it with every update.

My question is: what is the best approach for efficiently using the Python property when you need to do an expensive calculation? Should I cache the result after the first call and delete the cache in case of an update? Or is it better for me not to use the property and use the Foo.get_std() method Foo.get_std() ?

+7
python properties
source share
1 answer

You can usually do this with caching. For example, you can write:

 class Foo: def __int__(self, also, other, arguments): # ... self._std = None @property def std(self): if self._std is None: # ... calculate standard deviation self._std = ... return self._std def alter_state(self, some, arguments): # update state self._std = None 

So here we have the std property, but also the _std attribute. If the standard deviation has not yet been calculated, or you change the state of the object so that the standard deviation can change, we set _std to None . Now, if we turn to .std , we first check to see if _std None . If so, we calculate the standard deviation and store it in _std and return. Thus, if the object has not changed, we can simply get it later.

If we change the object so that the standard deviation can change, we return _std back to None to force a re-evaluation if we get access to .std .

If we change the state of the Foo object twice before repeating the standard deviation, we only recount it once. Thus, you can often modify the Foo object, and there are no additional costs (next to) (except for setting self._std - None ). Therefore, if you have a huge data set, and you are updating it a lot, you will only make an effort to calculate the standard deviation again, when you really need it.

In addition, it may also be an opportunity to update statistical measures in case it is (very) cheap. Say, for example, you have a list of objects that you often update in bulk. If you increase all elements with a constant, then the average value will also increase with this constant. Thus, functions that change state, so that some metrics can be easily changed, can update metrics, rather than create these None .

Note that .std is a property or the function does not matter. The user does not need to know how often this needs to be calculated. The std() function ensures that after its calculation, the second search will be quite fast.

+7
source share

All Articles