1

I have 2 integer class variables and a third class variable that should always be equal to the 2 class variables added. Is there a way that I could create a pointer that would always equal var1 + var2 or is there a better way of doing this?

Code example:

class Example:
  def __init__(self):
    self.var1 = 0
    self.var2 = 0
    self.added_vars = self.var1 + self.var2 # This doesn't stay equal to the vars added when the vars change

  def increment(self):
    self.var1 += 1
    self.var2 += 1

  def __repr__(self):
    return str(self.added_vars)

ex = Example()
print(ex)
ex.increment()
print(ex)

Should print:

0
2

but instead, I get:

0
0
  • You can use [properties](https://docs.python.org/3.8/library/functions.html#property) to update added_vars, whenever var1 or var2 is changed. – Wups Sep 12 '20 at 06:31

2 Answers2

3

Define added_vars as a property. This way, you can access it as you would access any attribute, but you can dynamically recalculate it each time you access it. You can find more info about it for example in this question.

class Example:
    def __init__(self):
        self.var1 = 0
        self.var2 = 0

    def increment(self):
        self.var1 += 1
        self.var2 += 1
        
    @property
    def added_vars(self):
        return self.var1 + self.var2

    def __repr__(self):
        return str(self.added_vars)
    

e = Example()
print(e.var1, e.var2, e.added_vars)
# 0 0 0 
e.increment()
print(e.var1, e.var2, e.added_vars)
# 1 1 2
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
0

The answer is going to depend a lot on how expensive it is to perform the calculation and how often you call it compared each time the inputs are updated.

If the calculation is cheap or you are calling it exactly once for each time that the inputs are updated, then it will be convenient to implement it as a property, so that it is calculated on-the-fly when it is needed. (See Thierry Lathuille's answer for implementation details.)

However, if it is expensive to calculate and you might call it repeatedly without changing the inputs (here, var1 and var2), then your options are:

  • To add it as an explicit attribute (alongside var1 and var2) and perform the calcuation inside your increment method.

  • To use the cached property package, and then inside your increment method you force invalidation of the cache, (i.e. del self.__dict__['added_vars']), so that next time that the property is accessed it will be recalculated, but otherwise the cache will be used for repeated accesses. This has the advantage that you recalculate it only exactly as often as needed.

Note that cached-property is outside the standard library, but if you prefer not to install additional packages, you could also implement a cache yourself. For example:

class Example:

    def __init__(self):
        self.var1 = 0
        self.var2 = 0

    def increment(self):
        self.var1 += 1
        self.var2 += 1
        try:
            del self._added_vars
        except AttributeError:
            pass

    @property
    def added_vars(self):
        try:
            return self._added_vars
        except AttributeError:
            print("recalculating")
            self._added_vars = self.var1 + self.var2
            return self._added_vars

    def __repr__(self):
        return str(self.added_vars)


ex = Example()
print(ex)
ex.increment()
print(ex)
print(ex)

Gives:

recalculating
0
recalculating
2
2
alani
  • 12,573
  • 2
  • 13
  • 23