正如多次提到的,使用函数名是在 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__
如果你想查找调用者的文档字符串,那无论如何都行不通,因为你的 print-helper 可能存在于一个完全不同的模块中,具有完全不同的 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()。