DEV Community

Avnish
Avnish

Posted on

Python callback when variable changes

In Python, you can achieve the functionality of executing a callback when a variable changes using various techniques. One common method is to use properties or setter methods along with the observer pattern. Below, I'll provide five examples demonstrating different ways to implement this functionality, along with explanations and sample outputs.

Example 1: Using a Property

class VariableWatcher:
    def __init__(self):
        self._value = None

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value
        self.on_change(new_value)

    def on_change(self, new_value):
        print(f"Variable value changed to: {new_value}")


# Example usage
watcher = VariableWatcher()
watcher.value = 10
watcher.value = 20
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • We define a class VariableWatcher with a private attribute _value to store the variable value.
  • We define a value property with a setter method. When the value property is set, it triggers the setter method, which updates the _value attribute and calls the on_change method.
  • The on_change method is where you would put your callback logic. In this example, it simply prints the new value.
  • When you run this code, you'll see that the on_change method gets called each time the value property is set.

Output:

Variable value changed to: 10
Variable value changed to: 20
Enter fullscreen mode Exit fullscreen mode

Example 2: Using a custom setter method

class VariableWatcher:
    def __init__(self):
        self._value = None

    def set_value(self, new_value):
        self._value = new_value
        self.on_change(new_value)

    def on_change(self, new_value):
        print(f"Variable value changed to: {new_value}")


# Example usage
watcher = VariableWatcher()
watcher.set_value(10)
watcher.set_value(20)
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • This example is similar to the first one, but instead of using a property, we have a custom setter method set_value.
  • Whenever set_value is called, it updates the _value attribute and calls the on_change method.
  • The on_change method remains the same as in the previous example.

Output: (Same as Example 1)

Example 3: Using custom observer pattern

class VariableWatcher:
    def __init__(self):
        self._value = None
        self.observers = []

    def set_value(self, new_value):
        self._value = new_value
        self.notify(new_value)

    def add_observer(self, observer):
        self.observers.append(observer)

    def notify(self, new_value):
        for observer in self.observers:
            observer(new_value)


# Example usage
def callback(new_value):
    print(f"Variable value changed to: {new_value}")

watcher = VariableWatcher()
watcher.add_observer(callback)
watcher.set_value(10)
watcher.set_value(20)
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • This example implements a simple observer pattern.
  • The VariableWatcher class maintains a list of observers (callbacks).
  • The add_observer method allows adding new observers to the list.
  • When the set_value method is called, it updates the _value attribute and notifies all observers by calling them with the new value.
  • In this example, we define a callback function callback and add it as an observer.

Output: (Same as Example 1)

Example 4: Using property decorator with a function

class VariableWatcher:
    def __init__(self):
        self._value = None

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value
        self.on_change(new_value)

    def on_change(self, new_value):
        print(f"Variable value changed to: {new_value}")


# Example usage
watcher = VariableWatcher()

def callback(new_value):
    print(f"Callback: Variable value changed to: {new_value}")

watcher.value = 10
watcher.on_change = callback  # Replace the callback
watcher.value = 20
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • This example is similar to Example 1, but we're demonstrating that you can change the on_change behavior dynamically.
  • After creating an instance of VariableWatcher, we define a callback function.
  • We then replace the on_change method with this callback function dynamically by assigning it to the on_change attribute of the instance.
  • When value is updated, it triggers the on_change method, which now calls our callback function instead.

Output:

Variable value changed to: 10
Callback: Variable value changed to: 20
Enter fullscreen mode Exit fullscreen mode

Example 5: Using a library (watchdog)

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class MyHandler(FileSystemEventHandler):
    def on_modified(self, event):
        if event.src_path == "./myfile.txt":
            print("File modified! Callback triggered.")

# Example usage
observer = Observer()
observer.schedule(MyHandler(), path='.')
observer.start()

# Simulate file modification
with open("myfile.txt", "w") as f:
    f.write("Hello, world!")

observer.stop()
observer.join()
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • In this example, we use the watchdog library to monitor file system events.
  • We define a custom event handler MyHandler which inherits from FileSystemEventHandler.
  • We override the on_modified method to specify what should happen when a file is modified. In this case, it prints a message.
  • We create an Observer instance, attach our event handler to it, and start observing the current directory.
  • Then, we simulate a file modification by creating a file "myfile.txt" and writing some content to it.
  • Finally, we stop the observer and join it.

Output:

File modified! Callback triggered.
Enter fullscreen mode Exit fullscreen mode

These examples showcase different ways to implement callbacks when a variable changes in Python, ranging from basic property setters to more advanced techniques using libraries like watchdog.

Top comments (0)