Monkeypatching
If I understand your situation correctly, your use case is not really about decoration (modifying a function you write, in a standard manner) but rather about monkey patching: Modifying a function somebody else wrote without actually changing that function's definition's source code.
The idiom for what you then need is something like
import numpy as np # provide local access to the numpy module object
original_np_sqrt = np.sqrt
def my_improved_np_sqrt(x):
# do whatever you please, including:
# - contemplating the UncertainQuantity-ness of x and
# - calling original_np_sqrt as needed
np.sqrt = my_improved_np_sqrt
Of course, this can change only the future meaning of numpy.sqrt
,
not the past one.
So if anybody has imported numpy
before the above and has already used numpy.sqrt
in a way you would have liked to influence, you lose.
(And the name to which they map numpy
does not matter.)
But after the above code was executed, the meaning of numpy.sqrt
in all
modules (whether they imported numpy
before it or after it)
will be that of my_improved_np_sqrt
, whether the creators of those modules
like it or not (and of course unless some more monkeypatching of numpy.sqrt
is going on elsewhere).
Note that
- When you do weird things, Python can become a weird platform!
- When you do weird things, Python can become a weird platform!
- When you do weird things, Python can become a weird platform!
This is why monkey patching is not normally considered good design style. So if you take that route, make sure you announce it very prominently in all relevant documentation.
Oh, and if you do not want to modify other code than that which is
directly or indirectly executed from your own methods, you could
introduce a decorator that performs monkeypatching before the call
and un-monkeypatching (reassigning original_np_sqrt
)
after the call and apply that decorator to
all your functions in question.
Make sure you handle exceptions in that decorator then, so that
the un-monkeypatching is really executed in all cases.