【问题标题】:Documenting first-class-assigned functions记录一流分配的功能
【发布时间】:2016-12-20 13:57:50
【问题描述】:

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

【问题讨论】:

  • 我想应该注意的是,第一种方式定义的函数确实带有一个文档字符串,但我希望添加我自己的/覆盖它(add_relative.__doc__ = 'string' 不可能)。
  • 不幸的是,不能定义一个以numpy.ufunc 为基类的类。这样做会引发错误TypeError: type 'numpy.ufunc' is not an acceptable base type。当初始函数定义完美执行时,我真的不想为了能够添加文档字符串而从头开始编写整个函数。
  • 一般来说,以初始方式定义的函数的文档字符串可以通过分配给__doc__ 属性来更新,但这在这里不合适,因为该属性对于numpy.ufunc 是不可变的。

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


【解决方案1】:

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

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

覆盖了文档字符串
.. function:: sum_relative(a, b)

   <Docstring written in rst format>

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

所有问题都源于 numpy.ufunc__doc__ 属性是不可变的。如果有人知道为什么,我很想听听为什么。我猜测它来自用 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.wrapsfunctools.update_wrapper 之类的东西,但是numpy.ufunc__doc__ 成员显然是不可变的。

  • 我必须硬编码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
    
  • 它比原来的解决方案更冗长。我不介意,因为我现在有了文档字符串。

【讨论】:

    【解决方案2】:

    我认为这样的事情可能会奏效:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-16
      • 1970-01-01
      相关资源
      最近更新 更多