多次提到,使用函数名称是对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()
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):
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()。