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


71

我想从函数本身内部打印python函数的文档字符串。例如

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

目前,my_function在定义之后,我将直接执行此操作。

print my_function.__doc__

但宁愿让函数自己执行此操作。

我已经尝试在my_function内调用它print self.__doc__ print self.my_function.__doc__print this.__doc__但这没有用。

Answers:


78
def my_func():
    """Docstring goes here."""
    print my_func.__doc__

只要您不更改绑定到名称的对象,此方法就可以工作my_func

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

您会执行此操作的情况很少见,但确实会发生。

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

def passmein(func):
    def wrapper(*args, **kwargs):
        return func(func, *args, **kwargs)
    return wrapper

现在您可以执行以下操作:

@passmein
def my_func(me):
    print me.__doc__

这将确保您的函数获得对自身的引用(类似于self)作为其第一个参数,因此它始终可以获取正确函数的文档字符串。如果在方法上使用,则通常self成为第二个参数。


8
我真的很喜欢您的装饰器方法。与框架检查相比,它具有更多的Python语言功能和更低的风险,并且AND允许您避免使用函数名称。光滑!已投票!
FlipMcF 2012年

* args和** kwargs是否不应该位于最后一个代码段的my_func的参数列表中?还是只是简单地省略了其他参数,尽管程序员可以在函数定义中放入所需的任何其他参数。我不确定是否很清楚,尽管它确实在文本中说“作为第一个参数”。
RufusVS

这个想法是包装器需要能够接受任何args,因为它无法(在装饰时)知道包装的函数采用什么参数。然后它将传递给包装函数的所有参数。如果输入的号码有误,则此时会出错。
kindall

@FlipMcF,我同意这种方法很棒,但是此问题或答案中的哪些代码实际上执行了“框架检查”?编辑哦!另一个可能的答案如下:stackoverflow.com/a/25549647/1175496我应该说Ctrl+F:)
红豌豆(Red Pea)

10

这应该工作(在我的测试中,它也包括输出)。你可能会用__doc__而不是getdoc,但是我喜欢它,所以这就是我所使用的。另外,这不需要您知道类/方法/函数的名称。

类,方法和函数的示例。告诉我这是否不是您想要的东西:)

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

6

这有效:

def my_function():
  """Docstring for my function"""
  #print the Docstring here.
  print my_function.__doc__

my_function()

在Python 2.7.1中

这也适用:

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

但是,这不能单独工作:

class MyClass(object):
    def my_function(self):
        """Docstring for my function"""
        #print the Docstring here.
        print my_function.__doc__


foo = MyClass()

foo.my_function()

NameError:全局名称“ my_function”未定义


您的类方法只能工作,因为您之前在全局名称空间中将my_function定义为一个函数。尝试使用新鲜的python实例;)
Alex Leach 2012年

@jgritty您没有测试您的第二个片段。它不起作用
eyquem 2012年

@Alex Leach您是否在课堂上测试了代码段?实际上,这是行不通的
。。。– eyquem

@jgritty和Alex Leach。方法(类中定义的最重要的函数)无法知道它们的外部空间。看到这个问题(stackoverflow.com/questions/1765677/python-nested-classes-scope/…)和我的答案
eyquem

不,我没有,但是我认为jgritty可能已经做到了。只是测试了一下,它可以正常工作并且符合预期(更改方法的文档字符串,仍然打印功能文档字符串)。模块中定义的函数在类方法中可用。例如,有没有必要重新导入东西在一个类的方法,如果它是在脚本的顶级进口..
亚历克斯·里奇

4

有一个很简单的方法可以做到这一点,而目前还没有人提及:

import inspect

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

这就是您想要的。

这里没有任何幻想。发生的所有事情是,通过执行func.__doc__一个函数来延迟属性解析足够长的时间,以__doc__使它可以按预期工作。

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


2
但这不仅仅比它好print func.__doc__
Reed_Xia

2

您提出的问题就像类方法而不是函数。命名空间在这里很重要。对于函数来说,没问题print my_function.__doc__,因为my_function在全局命名空间中。

对于类方法,那print self.my_method.__doc__将是路要走。

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

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 )

有没有什么好方法不必重复方法名称本身?诸如此类。__doc__或其他?对不起进出口新的蟒蛇..
shane87

是的,不是真的。我浏览了dir(self.my_function),self.my_function.__func__看起来也许很有趣,但是仍然需要通过该对象模型进行访问。您可以添加如下功能:for method in dir(MyClass): if hasattr(getattr(MyClass,method),'__doc__'): print getattr( getattr( MyClass,method), '__doc__')
Alex Leach 2012年

显然,缩进不是太有用。我会把它放在最初的答案中……
Alex Leach 2012年

@ shane87,AlexLeach和MattLuongo:请参见我的回答,以获取不重复类/方法/函数名称的方法。
Tehnix 2012年

2

多次提到,使用函数名称是对globals()目录的动态查找。它仅在定义的模块中起作用,并且仅对全局函数起作用。如果要查找成员函数的doc字符串,则还需要从类名称中查找路径-这很麻烦,因为这些名称可能会很长:

def foo():
    """ this is foo """
    doc = foo.__doc__
class Foo:
    def bar(self):
       """ this is bar """
       doc = Foo.bar.__doc__

相当于

def foo():
    """ this is foo """
    doc = globals()["foo"].__doc__
class Foo:
    def bar(self):
       """ this is bar """
       doc = globals()["Foo"].bar.__doc__

如果您要查找调用方的doc字符串,则无论如何都将无法正常工作,因为您的打印帮助程序可能位于具有完全不同的globals()字典的完全不同的模块中。唯一正确的选择是查看堆栈框架-但是Python没有给您正在执行的功能对象,它仅具有对“ f_code”代码对象的引用。但是请继续,因为该函数还引用了“ f_globals”。因此,您可以编写一个函数来获取调用方的文档,就像这样,并从中获得一个自己的文档字符串。

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__

让我们去测试一下:

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

结果输出

 this is foo 
 this is bar 
None
None
 showing my doc 

实际上,大多数人只希望自己的doc字符串将其作为参数传递,但是被调用的helper函数可以自行查找所有字符串。我在单元测试代码中使用了此代码,有时可以方便地填充一些日志或将doc字符串用作测试数据。这就是为什么给出的get_caller_doc()只查找全局测试函数和测试类的成员函数的原因,但是我想这对于大多数想了解doc字符串的人来说已经足够了。

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)

要使用sys._getframe(1)来定义正确的get_frame_doc(frame),请交给reader()。


1

尝试:

class MyClass():
    # ...
    def my_function(self):
        """Docstring for my function"""
        print MyClass.my_function.__doc__
        # ...

(*)之后有一个冒号(:my_function()


1
抱歉,我的愚蠢self.my_function .__ doc__实际上有效
shane87

0

print __doc__ 刚刚类声明后,,前def __init__,会在您每次启动一个对象与上课时间打印文档字符串到控制台


但是问题是要报告是否已加入某个功能,而不是在实例化类时报告。
RufusVS

对于那个很抱歉。那将是被接受的答案中的内容。打印func_name .__ doc__
emorphus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.