我通过使用Python函数的第一类特性定义了一个函数,如下所示:
add_relative = np.frompyfunc(lambda a, b: (1 + a) * (1 + b) - 1, 2, 1)
要么我需要一种方法来将docstring添加到定义的函数中,或者使用更常见的格式来实现相同的功能,这样我就可以用正常的方式编写文档字符串:
def add_relative(a, b):
"""
Docstring
"""
return np.frompyfunc(lambda a, b: (1 + a) * (1 + b) - 1, 2, 1)(a, b)
在调用函数时起作用,如
add_relative(arr1, arr2)
但我失去了调用方法的能力,例如
add_relative.accumulate(foo_arr, dtype=np.object)
我想这是因为在使用frompyfunc
时,该函数更像是一个类,来自ufunc
。
我认为我可能需要定义一个类,而不是一个函数,但我不确定如何。我会好的,因为那时我可以很容易地正常添加文档字符串。
我对此coding-style
进行了标记,因为原始方法有效,但根本无法轻松记录,如果标题不清楚,我很抱歉,我不知道正确词汇来形容这一点。
答案 0 :(得分:1)
更新1:
关闭,但这仍然不够好。因为装饰函数的__doc__
属性无法更新,并且因为Sphinx仍然只选取装饰函数的文档字符串,所以这并不能解决我的问题。
更新2: 我在下面提出的解决方案很适合源代码中的文档。对于使用Sphinx的文档,我最终只是用
覆盖了文档字符串.. function:: sum_relative(a, b)
<Docstring written in rst format>
它很丑陋,它是hacky和它的手册,但这意味着我在源代码中有很好的文档,而且我在Sphinx中有很好的文档。
所有问题都源于__doc__
的{{1}}属性是不可变的这一事实。如果有人知道为什么,我很想知道为什么。我猜测的事情与它用C语言写的东西有关,而不是纯粹的Python。无论如何,它非常烦人。
我发现我可以使用装饰器解决问题以应用numpy.ufunc
。
我编写基函数(原始示例中的lambda)并正常添加文档字符串然后应用装饰器:
np.frompyfunc()
由于以下原因,它不是一个完美的解决方案:
def as_ufunc(func):
return np.frompyfunc(func, 2, 1)
@as_ufunc
def sum_relative(a, b):
"""
Docstring
"""
return (1 + a) * (1 + b) - 1
被sum_relative.__doc__
覆盖为通用且无用的文档字符串。我不介意在这里,因为我非常关心从文档字符串中使用Sphinx生成的文档,而不是以编程方式访问它。您可能会考虑尝试frompyfunc
或functools.wraps
之类的内容,但functools.update_wrapper
的{{1}}成员显然是不可变的。
我必须对__doc__
的后两个参数进行硬编码。我不介意在这里,因为我在这里使用它的所有情况都需要相同的值。
编辑:有可能绕过上述观点,它有点冗长,但并不多:
numpy.ufunc
答案 1 :(得分:1)
我认为类似的方法可能有用:
UFUNC_ATTRS = (
'nin',
'accumulate',
# etc...
)
def redirectattribtues(destination):
def decorator(func):
for attribute in UFUNC_ATTRS:
setattr(func, attribute, getattr(destination, attribute))
return func
return decorator
ufunc = np.frompyfunc(lambda a, b: (1 + a) * (1 + b) - 1, 2, 1)
@redirectattribtues(destination=ufunc)
def add_relative(a, b):
"""
Docstring
"""
return ufunc(a, b)
# test
arr1 = np.array(list(range(0, 10)))
arr2 = np.array(list(range(10, 20)))
print(add_relative(arr1, arr2))
print(add_relative.accumulate(arr1, dtype=object))