我对python函数装饰器有点了解。我认为我的问题的答案是否定的,但我想确定。使用装饰器和x = np.array([1,2,3])
的numpy数组,我可以覆盖x.sqrt()
并更改行为。有没有办法在Python中覆盖np.sqrt(x)
?
用例:处理quantities package。希望能够在不更改当前使用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)
答案 0 :(得分:5)
如果我理解你的情况,你的用例实际上不是关于装饰(以标准方式修改你写的功能) 而是关于猴子补丁: 修改其他人编写的函数而不实际更改该函数的定义的源代码。
你需要的习惯用语是
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
更多的monkeypatching
正在其他地方进行。)
请注意
这就是为什么猴子补丁通常不被认为是好的设计风格。 因此,如果您采取这种方式,请确保您非常突出地宣布它 在所有相关文件中。
哦,如果你不想修改其他代码而不是修改代码
你可以直接或间接地从你自己的方法执行
介绍一个在调用之前执行monkeypatching的装饰器
和un-monkeypatching(重新分配original_np_sqrt
)
在调用之后并将该装饰器应用于
你所有的功能都有问题。
确保你在那个装饰器中处理异常,这样就可以了
在所有情况下都真正执行了非monkeypatching。
答案 1 :(得分:1)
也许,正如BrenBarn所说,
np.sqrt = decorator(np.sqrt)
因为装饰器只是一个可调用的,它接受一个对象并返回一个修改过的对象。