如何以编程方式设置文档字符串?

时间:2010-10-30 02:22:02

标签: python docstring

我有一个返回函数的包装函数。有没有办法以编程方式设置返回函数的docstring?如果我可以写信__doc__,我会执行以下操作:

def wrapper(a):
    def add_something(b):
       return a + b
    add_something.__doc__ = 'Adds ' + str(a) + ' to `b`'
    return add_something

然后我可以做

>>> add_three = wrapper(3)
>>> add_three.__doc__
'Adds 3 to `b`

但是,由于__doc__是只读的,我不能这样做。什么是正确的方法?


编辑:好的,我想保持这个简单,但当然这不是我真正想做的事情。即使一般__doc__在我的情况下是可写的,但它不是。

我正在尝试自动为unittest创建测试用例。我有一个包装函数,它创建一个类对象,它是unittest.TestCase的子类:

import unittest
def makeTestCase(filename, my_func):
    class ATest(unittest.TestCase):
        def testSomething(self):
            # Running test in here with data in filename and function my_func
            data  = loadmat(filename)
            result = my_func(data)
            self.assertTrue(result > 0)

    return ATest

如果我创建此类并尝试设置testSomething的文档字符串,则会收到错误消息:

>>> def my_func(): pass
>>> MyTest = makeTestCase('some_filename', my_func)
>>> MyTest.testSomething.__doc__ = 'This should be my docstring'
AttributeError: attribute '__doc__' of 'instancemethod' objects is not writable

6 个答案:

答案 0 :(得分:45)

instancemethod从其__func__获取其文档字符串。改为更改__func__的文档字符串。 (函数的__doc__属性是可写的。)

>>> class Foo(object):
...     def bar(self):
...         pass
...
>>> Foo.bar.__func__.__doc__ = "A super docstring"
>>> help(Foo.bar)
Help on method bar in module __main__:

bar(self) unbound __main__.Foo method
    A super docstring

>>> foo = Foo()
>>> help(foo.bar)
Help on method bar in module __main__:

bar(self) method of __main__.Foo instance
    A super docstring

来自2.7 docs

  

用户定义的方法

     

用户定义的方法对象组合了一个类,一个类实例(或None)和任何可调用的      对象(通常是用户定义的函数)。

     

特殊的只读属性:im_self是类实例对象,im_func是函数      宾语; im_class是绑定方法的im_self类或要求的类      未绑定方法的方法; __doc__是方法的文档(与...相同)      im_func.__doc__); __name__是方法名称(与im_func.__name__相同);      __module__是定义方法的模块的名称,如果不可用,则为None。

     

在版本2.2中更改:im_self用于引用定义方法的类。

     

版本2.6中已更改:对于3.0向前兼容性, im_func也可用作      __func__和im_self为__self__

答案 1 :(得分:18)

我会将docstring传递给工厂函数并使用type手动构建类。

def make_testcase(filename, myfunc, docstring):
    def test_something(self):
        data = loadmat(filename)
        result = myfunc(data)
        self.assertTrue(result > 0)

    clsdict = {'test_something': test_something,
               '__doc__': docstring}
    return type('ATest', (unittest.TestCase,), clsdict)

MyTest = makeTestCase('some_filename', my_func, 'This is a docstring')

答案 2 :(得分:6)

只需使用装饰器。这是你的情况:

def add_doc(value):
    def _doc(func):
        func.__doc__ = value
        return func
    return _doc

import unittest
def makeTestCase(filename, my_func):
    class ATest(unittest.TestCase):
        @add_doc('This should be my docstring')
        def testSomething(self):
            # Running test in here with data in filename and function my_func
            data  = loadmat(filename)
            result = my_func(data)
            self.assertTrue(result > 0)

    return ATest

def my_func(): pass

MyTest = makeTestCase('some_filename', my_func)
print MyTest.testSomething.__doc__
> 'This should be my docstring'

这是一个类似的用例:Python dynamic help and autocomplete generation

答案 3 :(得分:6)

这是对__doc__类的type属性无法更改的补充。有趣的是,只有使用类型创建类,这才是真实的。只要您使用元类,您实际上只需更改__doc__即可。

该示例使用abc(AbstractBaseClass)模块。它使用特殊的ABCMeta元类

import abc

class MyNewClass(object):
    __metaclass__ = abc.ABCMeta

MyClass.__doc__ = "Changing the docstring works !"

help(MyNewClass)

将导致

"""
Help on class MyNewClass in module __main__:

class MyNewClass(__builtin__.object)
 |  Changing the docstring works !
"""

我认为这应该是一个评论,但仍然收集我的前50分......

答案 4 :(得分:4)

仅当您的对象属于“type”类型时,

__doc__才可写。

在您的情况下,add_three是一个函数,您只需将__doc__设置为任何字符串。

答案 5 :(得分:0)

如果您尝试自动生成unittest.TestCase子类,则可能会有更多里程覆盖其shortDescription方法。

这是将基础文档字符串向下拖动到第一行的方法,如正常unittest输出中所示;覆盖它足以让我们控制TeamCity等报告工具中出现的内容,这正是我们所需要的。