如何从函数本身内部打印python函数的文档字符串?

发布于 2024-12-26 08:02:57 字数 426 浏览 1 评论 0原文

我想从函数本身内部打印 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__ 但这不起作用。

I want to print the docstring of a python function from inside the function itself.
for eg.

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

At the moment I am doing this directly after my_function has been defined.

print my_function.__doc__

But would rather let the function do this itself.

I have tried calling print self.__doc__ print self.my_function.__doc__ and print this.__doc__ inside my_function but this did not work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

安静被遗忘 2025-01-02 08:02:57
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 将成为第二个参数。

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

This will work as long as you don't change the object bound to the name 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

Situations in which you'd do this are rather rare, but they do happen.

However, if you write a decorator like this:

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

Now you can do this:

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

And this will ensure that your function gets a reference to itself (similar to self) as its first argument, so it can always get the docstring of the right function. If used on a method, the usual self becomes the second argument.

风启觞 2025-01-02 08:02:57

这应该有效(在我的测试中它确实有效,还包括输出)。您可能可以使用 __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

This should work (in my tests it does, also included output). You could probably use __doc__ instead of getdoc, but I like it, so thats just what i used. Also, this doesn't require you to know the names of the class/method/function.

Examples both for a class, a method and a function. Tell me if it's not what you were looking for :)

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
怀里藏娇 2025-01-02 08:02:57

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

import inspect

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

这就是你想要的。

这里没有什么奇怪的事情发生。所发生的一切是,通过在函数中执行 func.__doc__ ,可以将属性解析推迟足够长的时间,以便在其上查找 __doc__ 按您的预期工作。

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

There's quite a simple method for doing this that nobody has mentioned yet:

import inspect

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

And this does what you want.

There's nothing fancy going on here. All that's happening is that by doing func.__doc__ in a function defers attribute resolution long enough to have looking up __doc__ on it work as you'd expect.

I use this with docopt for console script entry points.

海螺姑娘 2025-01-02 08:02:57

这有效:

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'未定义

This works:

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

my_function()

in Python 2.7.1

This also works:

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

This however, will not work on its own:

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: global name 'my_function' is not defined

别在捏我脸啦 2025-01-02 08:02:57

您提出的问题就像是类方法而不是函数。命名空间在这里很重要。对于函数,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 )

You've posed your question like a class method rather than a function. Namespaces are important here. For a function, print my_function.__doc__ is fine, as my_function is in the global namespace.

For a class method, then print self.my_method.__doc__ would be the way to go.

If you don't want to specify the name of the method, but rather pass a variable to it, you can use the built-in functions hasattr(object,attribute) and getattr(obj,attr), which do as they say, allowing you to pass variables in with strings being the name of a method. e.g.

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 )
噩梦成真你也成魔 2025-01-02 08:02:57

正如多次提到的,使用函数名称是在 globals() 目录中进行动态查找。它仅适用于定义的模块,并且仅适用于全局函数。如果你想找出成员函数的文档字符串,你还需要从类名中查找路径 - 这非常麻烦,因为这些名称可能会很长:

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__

如果你想查找文档调用者的字符串,无论如何都不会工作,因为您的打印助手可能位于具有完全不同的 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 

实际上,大多数人希望自己的文档字符串只是将其作为参数传递,但是被调用的辅助函数可以自行查找它。我在单元测试代码中使用它,有时可以方便地填充一些日志或使用文档字符串作为测试数据。这就是为什么所提供的 get_caller_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() 。

As noted many times, using the function name is a dynamic lookup in the globals() directory. It only works in the module of the definition and only for a global function. If you want to find out the doc string of a member function, you would need to also lookup the path from the class name - which is quite cumbersome as these names can get quite long:

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

is equivalent to

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

If you want to look up the doc string of the caller, that won't work anyway as your print-helper might live in a completely different module with a completely different globals() dictionary. The only correct choice is to look into the stack frame - but Python does not give you the function object being executed, it only has a reference to the "f_code" code object. But keep going, as there is also a reference to the "f_globals" of that function. So you can write a function to get the caller's doc like this, and as a variation from it, you get your own doc string.

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__

and let's go to test it:

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

results in this output

 this is foo 
 this is bar 
None
None
 showing my doc 

Actually, most people want their own doc string only to hand it down as an argument, but the called helper function can look it up all on its own. I'm using this in my unittest code where this is sometimes handy to fill some logs or to use the doc string as test data. That's the reason why the presented get_caller_doc() only looks for global test functions and member functions of a test class, but I guess that is enough for most people who want to find out about the doc string.

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)

To define a proper get_frame_doc(frame) with sys._getframe(1) is left to the reader().

似梦非梦 2025-01-02 08:02:57

尝试:

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

(*) my_function() 之后缺少一个冒号 (:)

Try:

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

(*) There was a colon (:) missing after my_function()

冷默言语 2025-01-02 08:02:57

如果您使用 Test 类来确保文档字符串出现在每个测试中,那么有效的方法就是这样。

def setup_method(self, method):
    print(getattr(self, method.__name__).__doc__)
        
     

这将在执行之前打印每个方法的文档字符串,或者您可以在teardown_method 上传递相同的脚本以在每个测试用例的末尾打印它。

If you're using Test class to make sure that doc string will appear in each test, then the efficient approach would be this.

def setup_method(self, method):
    print(getattr(self, method.__name__).__doc__)
        
     

This will print doc string of each method before it gets executed or you can past the same script on teardown_method to print it in the end of each test case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文