Decorating Class by Monkey Patching in Python with Example

In Python, we can decorate class using monkey patching approach. Decorating class is quite useful when we need to attach some methods to all instances of that class.

Python Source Code: Decorating Class

Let's take an example of adding log functionality to each instances of different class to illustrate decorating class using monkey patching concept.


# Decorator functions
def log_info(self):
    from datetime import datetime, timezone
    called_at = datetime.now(timezone.utc)
    message = '{0} executed. Logged at {1}'.format(self.__class__.__name__, called_at)
    return message

def logger(cls):
    cls.log = log_info # monkey patching
    return cls

# decorating class in action
@logger
class A:
    pass

@logger
class B:
    pass

# Creating instances
a1 = A()
b1 = B()
a2 = A()
b2 = B()
b3 = B()

# Printing log message
print(a1.log())
print(b1.log())
print(a2.log())
print(b2.log())
print(b3.log())

Output

A executed. Logged at 2020-05-27 09:29:52.088577+00:00
B executed. Logged at 2020-05-27 09:29:52.088577+00:00
A executed. Logged at 2020-05-27 09:29:52.089579+00:00
B executed. Logged at 2020-05-27 09:29:52.089579+00:00
B executed. Logged at 2020-05-27 09:29:52.089579+00:00

Explanation

To understand how these class are decorated, let's analyze following code:


@logger
class A:
    pass

This code can be written as:


class A:
    pass

A = logger(A)

So, we are passing class A to logger function which is received in variable cls. Where it monkey patches to add log attribute. And log attribute is essentially log_info() function which returns log message.

This is how log attribute is attached to every instances of classes which are decorated.