如何从函数本身内部打印python函数的Docstring?

How to print Docstring of python function from inside the function itself?

我想从函数本身内部打印python函数的docstring。例如

1
2
3
def my_function(self):
 """Doc string for my function."""
  # print the Docstring here.

目前,我是在定义了my_function之后直接这样做的。

1
print my_function.__doc__

但更愿意让函数自己来做。

我试过在我的函数内调用print self.__doc__print self.my_function.__doc__print this.__doc__,但这不起作用。


1
2
3
def my_func():
   """Docstring goes here."""
    print my_func.__doc__

只要您不将绑定到名称my_func的对象更改,这将有效。

1
2
3
4
5
new_func_name = my_func
my_func = None

new_func_name()
# doesn't print anything because my_func is None and None has no docstring

你这样做的情况是相当罕见的,但它们确实发生了。

但是,如果您编写这样的装饰器:

1
2
3
4
def passmein(func):
    def wrapper(*args, **kwargs):
        return func(func, *args, **kwargs)
    return wrapper

现在您可以这样做:

1
2
3
@passmein
def my_func(me):
    print me.__doc__

这将确保您的函数得到对自身的引用(类似于self),作为它的第一个参数,因此它总是可以得到正确函数的docstring。如果用于方法,通常的self将成为第二个参数。


这应该有效(在我的测试中,它确实有效,还包括输出)。你可以用__doc__代替getdoc,但我喜欢,所以我就是这么用的。此外,这不需要您知道类/方法/函数的名称。

类、方法和函数的示例。如果不是你要找的,告诉我:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from inspect import *

class MySelfExplaningClass:
   """This is my class document string"""

    def __init__(self):
        print getdoc(self)

    def my_selfexplaining_method(self):
       """This is my method document string"""
        print getdoc(getattr(self, getframeinfo(currentframe()).function))


explain = MySelfExplaningClass()

# Output: This is my class document string

explain.my_selfexplaining_method()

# Output: This is my method document string

def my_selfexplaining_function():
   """This is my function document string"""
    print getdoc(globals()[getframeinfo(currentframe()).function])

my_selfexplaining_function()

# Output: This is my function document string


这工作:

1
2
3
4
5
6
def my_function():
 """Docstring for my function"""
  #print the Docstring here.
  print my_function.__doc__

my_function()

在Python 2.7.1中

这也适用于:

1
2
3
4
5
6
7
8
9
10
11
class MyClass(object):
    def my_function(self):
       """Docstring for my function"""
        #print the Docstring here, either way works.
        print MyClass.my_function.__doc__
        print self.my_function.__doc__


foo = MyClass()

foo.my_function()

然而,这不会单独起作用:

1
2
3
4
5
6
7
8
9
10
class MyClass(object):
    def my_function(self):
       """Docstring for my function"""
        #print the Docstring here.
        print my_function.__doc__


foo = MyClass()

foo.my_function()

名称错误:未定义全局名称"我的函数"


有一个非常简单的方法可以做到这一点,但还没有人提到:

1
2
3
4
5
import inspect

def func():
   """Doc string"""
    print inspect.getdoc(func)

这就是你想要的。

这里没有什么好奇心。所发生的一切是,通过在函数中执行func.__doc__,可以将属性解析延迟足够长的时间,以便在它上查找__doc__,如您所期望的那样工作。

我将它与docopt一起用于控制台脚本入口点。


你提出的问题就像是一个类方法而不是一个函数。命名空间在这里很重要。对于一个函数,print my_function.__doc__是可以的,因为我的函数在全局名称空间中。

对于一个类方法,那么print self.my_method.__doc__将是前进的道路。

如果您不想指定方法的名称,而是传递一个变量给它,您可以使用内置函数hasattr(object,attribute)和getattr(obj,attr),正如它们所说的那样,允许您通过字符串作为方法名传递变量。例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass:
    def fn(self):
       """A docstring"""
        print self.fn.__doc__

def print_docstrings(object):
   for method in dir( object ):
       if method[:2] == '__':  # A protected function
           continue
       meth = getattr( object, method )
       if hasattr( meth , '__doc__' ):
           print getattr( meth , '__doc__' )

x = MyClass()
print_docstrings( x )


如前所述,使用函数名是globals()目录中的动态查找。它只在定义的模块中工作,并且只适用于全局函数。如果要查找成员函数的Doc字符串,还需要从类名中查找路径-这很麻烦,因为这些名称可能会变长:

1
2
3
4
5
6
7
def foo():
   """ this is foo"""
    doc = foo.__doc__
class Foo:
    def bar(self):
      """ this is bar"""
       doc = Foo.bar.__doc__

相当于

1
2
3
4
5
6
7
def foo():
   """ this is foo"""
    doc = globals()["foo"].__doc__
class Foo:
    def bar(self):
      """ this is bar"""
       doc = globals()["Foo"].bar.__doc__

如果您想查找调用方的DOC字符串,那么这将不起作用,因为您的打印助手可能与完全不同的全局()字典位于完全不同的模块中。唯一正确的选择是查看堆栈帧——但是Python没有给您执行正在执行的函数对象,它只引用了一个"fxCal码"代码对象。但是继续前进,因为还有一个函数的"fGULL"的引用。因此,您可以编写一个函数来获取调用方的doc,并且作为变量,您可以得到自己的DOC字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
import inspect

def get_caller_doc():
    frame = inspect.currentframe().f_back.f_back
    for objref in frame.f_globals.values():
        if inspect.isfunction(objref):
            if objref.func_code == frame.f_code:
                return objref.__doc__
        elif inspect.isclass(objref):
            for name, member in inspect.getmembers(objref):
                if inspect.ismethod(member):
                    if member.im_func.func_code == frame.f_code:
                        return member.__doc__

让我们来测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def print_doc():
   print get_caller_doc()

def foo():
  """ this is foo"""
   print_doc()

class Foo:
    def bar(self):
      """ this is bar"""
       print_doc()

def nothing():
    print_doc()

class Nothing:
    def nothing(self):
        print_doc()

foo()
Foo().bar()

nothing()
Nothing().nothing()

# and my doc

def get_my_doc():
    return get_caller_doc()

def print_my_doc():
   """ showing my doc"""
    print get_my_doc()

print_my_doc()

在这个输出中的结果

1
2
3
4
5
 this is foo
 this is bar
None
None
 showing my doc

实际上,大多数人只希望自己的文档字符串作为一个参数传递下去,但是被调用的helper函数可以自己查找所有这些字符串。我在我的UnitTest代码中使用它,在这里有时填充一些日志或使用文档字符串作为测试数据很方便。这就是为什么所呈现的get_caller_doc()只查找测试类的全局测试函数和成员函数的原因,但我想这对于大多数想了解文档字符串的人来说已经足够了。

1
2
3
4
5
6
7
8
9
class FooTest(TestCase):
    def get_caller_doc(self):
        # as seen above
    def test_extra_stuff(self):
       """ testing extra stuff"""
        self.createProject("A")
    def createProject(self, name):
        description = self.get_caller_doc()
        self.server.createProject(name, description)

定义一个合适的get_frame_doc(frame)with sys._getframe(1)留给reader()。


尝试:

1
2
3
4
5
6
class MyClass():
    # ...
    def my_function(self):
       """Docstring for my function"""
        print MyClass.my_function.__doc__
        # ...

(*)my_function()后结肠(:缺失)


插入print __doc__在类声明之后,在def __init__之前,每次用类初始化对象时,都会将文档字符串打印到控制台。