Search code examples
python-3.xmetaprogrammingpython-importmonkeypatchingpython-internals

Python - monkey patch fails, why?


I want to monkey patch on f(*args, **kwargs) from an installed module. I use the idea of decorator on my own code, but other methods from the installed module fails to call f correctly.

Here is an example:

import numpy as np

def log(func):
    def wrapper(*args, **kwargs):
        print('logging')
        return func(*args, **kwargs)
    return wrapper

if __name__ == "__main__":
    a1 = np.asarray([0, 1, 2])
    print(f'a1={a1}')

    a2 = np.array([0, 1, 2])
    print(f'a2={a2}')

    np.array = log(np.array)

    a3 = np.asarray([0, 1, 2])
    print(f'a3={a3}')

    a4 = np.array([0, 1, 2])
    print(f'a4={a4}')

The output is:

a1=[0 1 2]
a2=[0 1 2]
a3=[0 1 2]
logging
a4=[0 1 2]

I would like the result to be:

a1=[0 1 2]
a2=[0 1 2]
logging
a3=[0 1 2]
logging
a4=[0 1 2]

since asarray calls array in the source code.

My questions are: 1. Why monkey patch fails? 2. How to fix it?


Solution

  • By np.array = log(np.array) you are changing which function the "public" name np.array refers to.

    But np.asarray is defined in the numpy.core.numeric module, which has its own "private" name to refer to that function. It is not affected by patching the public name.

    You would have to patch the private name:

    np.core.numeric.array = log(np.array)