我可以装饰显式函数调用如np.sqrt()吗?
我对Python中的函数装饰器有一点了解。我觉得我的问题答案是否定的,但我想确认一下。通过一个装饰器和一个numpy数组x = np.array([1,2,3])
,我可以重写x.sqrt()
来改变它的行为。那么,有没有办法在Python中重写np.sqrt(x)
呢?
使用场景:我正在使用quantities包。我希望能够对不确定的量进行平方根运算,而不需要更改当前使用np.sqrt()
的代码。
编辑:
我想修改np.sqrt
在quantities
包中的表现,使得以下代码可以正常工作(这三行代码的输出应该是一样的,注意使用np.sqrt()
时的不确定性为0)。我希望不需要最终用户修改他们的代码,而是在quantities
包中正确地包装/装饰np.sqrt()
。目前,许多numpy函数都被装饰过(见https://github.com/python-quantities/python-quantities/blob/ca87253a5529c0a6bee37a9f7d576f1b693c0ddd/quantities/quantity.py),但似乎只在调用x.func()
时有效,而不是numpy.func(x)
。
import numpy as np
import quantities as pq
x = pq.UncertainQuantity(2, pq.m, 2)
print x.sqrt()
>>> 1.41421356237 m**0.5 +/- 0.707106781187 m**0.5 (1 sigma)
print x**0.5
>>> 1.41421356237 m**0.5 +/- 0.707106781187 m**0.5 (1 sigma)
print np.sqrt(x)
>>> 1.41421356237 m**0.5 +/- 0.0 dimensionless (1 sigma)
2 个回答
也许,正如BrenBarn所说,
np.sqrt = decorator(np.sqrt)
因为装饰器其实就是一个可以被调用的东西,它接收一个对象,然后返回一个修改过的对象。
猴子补丁
如果我理解你的情况没错,你的需求其实不是在装饰(也就是以标准的方式修改你自己写的函数),而是关于猴子补丁:就是在不改变别人写的函数的源代码的情况下,修改这个函数的行为。
你需要的做法大概是这样的:
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
当然,这样做只会改变numpy.sqrt
将来的含义,而不会影响过去的含义。所以,如果在你执行上面的代码之前,有人已经导入了numpy
并使用了numpy.sqrt
,你就无法影响他们的用法。(而且他们如何引用numpy
也无所谓。)
但是在执行了上面的代码之后,所有模块中numpy.sqrt
的含义(无论他们是在之前还是之后导入numpy
)都会变成my_improved_np_sqrt
的含义,不管那些模块的创建者是否喜欢(当然,前提是没有其他地方对numpy.sqrt
进行更多的猴子补丁)。
需要注意的是:
- 当你做一些奇怪的事情时,Python可能会变得很奇怪!
- 当你做一些奇怪的事情时,Python可能会变得很奇怪!
- 当你做一些奇怪的事情时,Python可能会变得很奇怪!
这就是为什么猴子补丁通常不被认为是好的设计风格。所以如果你选择这种方式,确保在所有相关文档中非常明显地说明这一点。
哦,如果你不想修改其他代码,除了那些直接或间接从你自己方法中执行的代码,你可以引入一个装饰器,在调用之前进行猴子补丁,在调用之后再恢复原来的original_np_sqrt
,并将这个装饰器应用到你所有相关的函数上。确保在这个装饰器中处理异常,这样在所有情况下都能真正执行恢复操作。