记录第一类指定的功能

时间:2016-12-20 13:57:50

标签: python coding-style docstring first-class-functions numpy-ufunc

我通过使用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进行了标记,因为原始方法有效,但根本无法轻松记录,如果标题不清楚,我很抱歉,我不知道正确词汇来形容这一点。

2 个答案:

答案 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生成的文档,而不是以编程方式访问它。您可能会考虑尝试frompyfuncfunctools.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))