Как напечатать Docstring функции python из самой функции? - PullRequest
54 голосов
/ 11 января 2012

Я хочу напечатать строку документации функции python из самой функции. например,

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

В данный момент я делаю это сразу после определения my_function.

print my_function.__doc__

Но лучше позволить функции сделать это самостоятельно.

Я попытался вызвать print self.__doc__ print self.my_function.__doc__ и print this.__doc__ внутри my_function, но это не сработало.

Ответы [ 8 ]

63 голосов
/ 11 января 2012
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 голосов
/ 12 января 2012

Это должно работать (в моих тестах это также включало вывод). Возможно, вы могли бы использовать __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
5 голосов
/ 11 января 2012

Это работает:

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

Это, однако, не будет работать самостоятельно:1009 *

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' не определено

2 голосов
/ 11 января 2012

Вы задали свой вопрос как метод класса, а не как функцию.Пространства имен важны здесь.Для функции print my_function.__doc__ хорошо, так как my_function находится в глобальном пространстве имен.

Для метода класса, тогда print self.my_method.__doc__ будет подходящим вариантом.

Если вы неЕсли вы хотите указать имя метода, а вместо этого передать ему переменную, вы можете использовать встроенные функции hasattr (объект, атрибут) и 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 )
1 голос
/ 11 января 2017

Существует довольно простой способ сделать это, о котором еще никто не упомянул:

import inspect

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

И это делает то, что вы хотите.

Здесь нет ничего необычного. Все, что происходит, это то, что выполнение func.__doc__ в функции откладывает разрешение атрибута на достаточно долгое время, чтобы поиск __doc__ работал так, как вы ожидаете.

Я использую это с docopt для точек входа консольного скрипта.

1 голос
/ 28 августа 2014

Как уже много раз отмечалось, использование имени функции - это динамический поиск в каталоге globals ().Он работает только в модуле определения и только для глобальной функции.Если вы хотите узнать строку документа функции-члена, вам также необходимо найти путь к имени класса, что довольно громоздко, поскольку эти имена могут быть довольно длинными:

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

эквивалентноto

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__

, и давайте протестируем ее:

приводит к таким выводам

 this is foo 
 this is bar 
None
None
 showing my doc 

На самом деле, большинство людей хотят, чтобы их собственная строка документа передавала ее только в качестве аргумента, но вызываемая вспомогательная функция может самостоятельно все искать.Я использую это в своем коде unittest, где иногда удобно заполнять некоторые журналы или использовать строку документации в качестве тестовых данных.По этой причине представленный 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)

Чтобы определить правильный get_frame_doc (frame) с помощью sys._getframe (1), оставляем читателю ().

1 голос
/ 11 января 2012

Попробуйте:

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

(*) Отсутствует двоеточие (:) после my_function()

0 голосов
/ 08 марта 2017

вставка print __doc__ сразу после объявления класса, перед def __init__, строка документа будет выводиться на консоль каждый раз, когда вы инициируете объект с классом

...