w3resource

Python Attribute Logging Metaclass: Monitor Accesses

Python Metaprogramming: Exercise-4 with Solution

Attribute Logging Metaclass:

Write a Python metaclass “AttrLoggingMeta” that logs every time an attribute is accessed or modified.

Sample Solution:

Python Code :

# Define a metaclass AttrLoggingMeta
class AttrLoggingMeta(type):
    # Override the __new__ method to log attribute accesses
    def __new__(cls, name, bases, dct):
        # Iterate through class attributes
        for key, value in dct.items():
            # Exclude special methods
            if not key.startswith('__'):
                # Replace attribute with a logged version
                dct[key] = cls.log_access(key, value)
        # Call superclass's __new__ method to create the class
        return super().__new__(cls, name, bases, dct)
    
    # Define a static method to log attribute accesses
    @staticmethod
    def log_access(name, value):
        # If the attribute is a method, wrap it to log method calls
        if callable(value):
            def wrapper(*args, **kwargs):
                print(f"Calling method {name}")
                return value(*args, **kwargs)
            return wrapper
        else:
            # If the attribute is a property, log read and write operations
            return property(
                # Log attribute read operation
                fget=lambda self: AttrLoggingMeta.log_read(name, value, self),
                # Log attribute write operation
                fset=lambda self, v: AttrLoggingMeta.log_write(name, v, self)
            )
    
    # Define a static method to log attribute reads
    @staticmethod
    def log_read(name, value, instance):
        print(f"Reading attribute {name}")
        return value
    
    # Define a static method to log attribute writes
    @staticmethod
    def log_write(name, value, instance):
        print(f"Writing attribute {name} with value {value}")
        # Update instance dictionary with the new value
        instance.__dict__[name] = value

# Define a class LoggedClass using AttrLoggingMeta as its metaclass
class LoggedClass(metaclass=AttrLoggingMeta):
    # Define a class attribute foo
    foo = 42

    # Define a class method bar
    def bar(self):
        return 'baz'

# Create an instance of LoggedClass
instance = LoggedClass()
# Access and print the value of the foo attribute
print(instance.foo)  # Reading attribute foo
# Set the value of the foo attribute
instance.foo = 78    # Writing attribute foo with value 84
# Call the bar method
instance.bar()       # Calling method bar 

Output:

Reading attribute foo
42
Writing attribute foo with value 78
Calling method bar

Explanation:

  • Metaclass AttrLoggingMeta:
    • This metaclass is responsible for logging attribute accesses of classes that use it.
    • The "new" method is overridden to intercept attribute assignments and replace them with logged versions.
    • Inside "new", it iterates over the class attributes (excluding special methods) and replaces them with logged versions using the 'log_access' method.
  • Static Method log_access:
    • This method is called to replace each attribute with a logged version.
    • If the attribute is a method, it wraps it with a wrapper function that logs method calls.
    • If the attribute is a property, it replaces it with a property that logs read and write operations.
  • Static Methods log_read and log_write:
    • These methods are called to log read and write operations of properties.
    • They print messages indicating the attribute name and the operation being performed.
  • Class LoggedClass:
    • This class is an example demonstrating the use of the "AttrLoggingMeta" metaclass.
    • It contains a class attribute 'foo' and a method 'bar'.
  • Instance Creation and Testing:
    • An instance of 'LoggedClass' is created.
    • The value of the 'foo' attribute is accessed, demonstrating logging of attribute reads.
    • The value of the 'foo' attribute is changed, demonstrating logging of attribute writes.
    • The "bar" method is called, demonstrating logging of method calls.

Python Code Editor :

Have another way to solve this solution? Contribute your code (and comments) through Disqus.

Previous: Python Singleton Metaclass: Ensure One Instance.
Next: Python Dynamic Class Creation: Flexibility Unleashed

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Become a Patron!

Follow us on Facebook and Twitter for latest update.

It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.

https://w3resource.com/python-exercises/metaprogramming/python-metaprogramming-exercise-4.php