1

我有一个利用 Python 函数的一流特性定义的函数,如下所示:

add_relative = np.frompyfunc(lambda a, b: (1 + a) * (1 + b) - 1, 2, 1)

要么我需要一种将文档字符串添加到按原样定义的函数的方法,要么使用更常见的格式实现相同的目的,以便我可以以正常方式编写文档字符串:

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,因为原始方法有效,但不能轻易记录,如果标题不清楚,我很抱歉,我不知道描述这个的正确词汇。

4

2 回答 2

2

更新 1: 关闭,但这仍然不够好。因为__doc__装饰函数的属性无法更新,而且 Sphinx 仍然只获取装饰函数的文档字符串,所以这并不能解决我的问题。

更新 2: 我在下面提出的解决方案非常适合源代码中的文档。对于 Sphinx 的文档,我最终只是用

.. function:: sum_relative(a, b)

   <Docstring written in rst format>

它很丑,很hacky,而且是手动的,但这意味着我在源代码中有很好的文档,我在Sphinx中有很好的文档。

所有问题都源于 a 的__doc__属性numpy.ufunc是不可变的。如果有人知道为什么,我很想听听为什么。我猜测它来自用 C 编写的东西,而不是纯 Python。无论如何,这非常烦人。


我发现我可以使用装饰器来解决问题np.frompyfunc()

我编写基本函数(原始示例中的 lambda)并正常添加一个文档字符串,然后应用装饰器:

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__frompyfunc通用且无用的文档字符串覆盖。我不介意这里,因为我真的很关心从文档字符串中使用 Sphinx 生成的文档,而不是以编程方式访问它。你可能想尝试类似functools.wrapsor的东西functools.update_wrapper,但是__doc__a 的成员numpy.ufunc显然是不可变的。

  • 我必须硬编码后两个参数frompyfunc。我不介意在这里,因为我在这里使用它的所有案例都需要相同的值。

  • 编辑:有可能绕过上述观点,它有点冗长,但不多:

    def as_ufunc(nin, nout):
        def _decorator(func):
            return np.frompyfunc(func, nin, nout)
        return _decorator
    
    @as_ufunc(2, 1)
    def sum_relative(a, b):
        """
        Docstring
        """
        return (1 + a) * (1 + b) - 1
    
  • 它比原始解决方案更冗长。我不介意,因为我现在有了文档字符串。
于 2016-12-20T15:22:33.673 回答
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))
于 2020-04-28T17:23:03.793 回答