2

I want to be able to monitor the variable and have a function inside of my class be called when an instance of my class is changed.

class Example:
    def __init__(self, content):
        self.content = content

example1 = Example('testing')

example1.content = 'testing123'

I would like to be able to check if example1.content was changed/updated, and if it was changed, run some code.

Dango
  • 37
  • 5
  • Do https://stackoverflow.com/questions/13528213/observer-observable-classes-in-python or https://stackoverflow.com/questions/1904351/python-observer-pattern-examples-tips answer your questions? – omajid Jul 06 '20 at 20:28

2 Answers2

5

Is this what you're looking for?

class Example:
    def __init__(self, content):
        self.content = content

    def __setattr__(self, name, value):
        if name == 'content':
            if not hasattr(self, 'content'):
                print(f'constructor call with value: {value}')
            else:
                print(f'New value: {value}')
        super().__setattr__(name, value)


if __name__ == '__main__':
    example1 = Example('testing')
    example1.content = 'testing123'

Output:

constructor call with value: testing
New value: testing123
Balaji Ambresh
  • 4,977
  • 2
  • 5
  • 17
  • Is there a way for it to not run when the first instance is created and only after the instance is "edited"? – Dango Jul 06 '20 at 20:32
  • 1
    Intercepting every attempt to assign to an attribute to catch assignments to just one of them is fairly heavy-handed. The descriptor protocol already provides a way to detect which assignment you want to intercept, as implemented by the `property` class. – chepner Jul 06 '20 at 20:42
  • 1
    In this solution, you can check for the calling function and print the "change" if required. You can look at [this](https://stackoverflow.com/a/2654130/5967374) answer to get caller function name – Prateek Dorwal Jul 06 '20 at 20:47
  • 1
    this is a great answer.. very helpful, I learned something – Derek Eden Jul 06 '20 at 20:51
3

You could use a property setter in a class like this:

class Example:
    def __init__(self, content):
        self.content = content

    @property
    def content(self):
        return self._content

    @content.setter
    def content(self, value):
        if hasattr(self, '_content'):
            # do function call
            print("new content! {}".format(value))

        self._content = value


x = Example('thing')


x.content = 'newthing'
new content! newthing
C.Nivs
  • 12,353
  • 2
  • 19
  • 44