# In Groovy we can add interception to an instance (not to a whole class) by means of adding it to the instance metaclass # we can do something like that in Python by creating a new class that inherits the original class of the instance, and changing the class of the instance # in that new class we implement __getattribute__ class Person: def __init__(self, name): self.name = name def say_hi(self, person): #print("inside say_hi") return f"Hi person, I'm {self.name}" def add_interception_to_instance(obj, interceptor_fn): class Interceptor_class(obj.__class__): def __getattribute__(self, name): interceptor_fn(self, name) return object.__getattribute__(self, name) obj.__class__ = Interceptor_class p1 = Person("Xuan") print(p1.say_hi("Francois")) # Hi person, I'm Xuan def logger_interceptor_fn(obj, attr): print(f"intercepting access to {attr}") add_interception_to_instance(p1, logger_interceptor_fn) print(p1.say_hi("Francois")) #interception happens: # intercepting access to say_hi # intercepting access to name # Hi person, I'm Xuan print(isinstance(p1, Person)) # True # other instances of Person are not intercepted p2 = Person("Iyan") print(p2.say_hi("Francois")) # Hi person, I'm Iyan