我可以装饰显式函数调用,如np.sqrt()

时间:2014-03-24 02:59:58

标签: python numpy decorator python-decorators

我对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)

2 个答案:

答案 0 :(得分:5)

的Monkeypatching

如果我理解你的情况,你的用例实际上不是关于装饰(以标准方式修改写的功能) 而是关于猴子补丁: 修改其他人编写的函数而不实际更改该函数的定义的源代码。

你需要的习惯用语是

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 正在其他地方进行。)

请注意

  1. 当你做奇怪的事情时,Python可以成为一个奇怪的平台!
  2. 当你做奇怪的事情时,Python可以成为一个奇怪的平台!
  3. 当你做奇怪的事情时,Python可以成为一个奇怪的平台!
  4. 这就是为什么猴子补丁通常不被认为是好的设计风格。 因此,如果您采取这种方式,请确保您非常突出地宣布它 在所有相关文件中。

    哦,如果你不想修改其他代码而不是修改代码 你可以直接或间接地从你自己的方法执行 介绍一个在调用之前执行monkeypatching的装饰器 和un-monkeypatching(重新分配original_np_sqrt) 在调用之后并将该装饰器应用于 你所有的功能都有问题。 确保你在那个装饰器中处理异常,这样就可以了 在所有情况下都真正执行了非monkeypatching。

答案 1 :(得分:1)

也许,正如BrenBarn所说,

np.sqrt = decorator(np.sqrt)

因为装饰器只是一个可调用的,它接受一个对象并返回一个修改过的对象。