-2

I'm trying to calculate a value once (because it takes a long time) and then store the value so that it can be used again.
I am aware types.MethodType but I want to just reference a property and not have to call it.

import types

class stuff:
  @property
  def compute_once(self):
    takes_long_time_to_calculate = 5 - 2
    self.compute_once = takes_long_time_to_calculate
    return takes_long_time_to_calculate

instance = stuff()

print(instance.compute_once)
print(instance.compute_once)

Error Message:

Traceback (most recent call last):
  File "try.py", line 12, in <module>
    print(instance.compute_once)
  File "try.py", line 7, in compute_once
    self.compute_once = takes_long_time_to_calculate
AttributeError: can't set attribute
William Rusnack
  • 908
  • 8
  • 15

1 Answers1

2

You just need to store the result of the expensive calculation in another attribute. You can mark it as private by giving it a name with a single leading underscore. That's just a convention though, Python doesn't do anything special with such attributes, but users of your code will know that they shouldn't meddle directly with it. Python doesn't really have private attributes, instead it has the philosophy of "we're all consenting adults here". See https://stackoverflow.com/a/70736/4014959

class Stuff:
    def __init__(self):
        self._compute_once = None

    @property
    def compute_once(self):
        if self._compute_once is None:
            print('Doing expensive calculation')
            self._compute_once = 2 * 3 * 5 * 7
        return self._compute_once

instance = Stuff()

print(instance.compute_once)
print(instance.compute_once)

output

Doing expensive calculation
210
210

We initialize ._compute_once to None and only perform the expensive calculation if ._compute_once is None. We can force re-calculation at any time by resetting ._compute_once to None.

For more info on how properties work, please read the excellent Descriptor HowTo Guide by Python core developer (and SO veteran) Raymond Hettinger.

Community
  • 1
  • 1
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182