web-dev-qa-db-ja.com

関数の内部からpython関数のDocstringを印刷するには?

関数の内部からpython関数のdocstringを印刷したい。例えば。

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__を呼び出してみましたが、これは機能しませんでした。

58
shane87
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と同様)を最初の引数として取得できるようになるため、常に適切な関数のdocstringを取得できます。メソッドで使用する場合、通常のselfが2番目の引数になります。

65
kindall

これは動作するはずです(私のテストでは、出力も含まれています)。おそらくgetdocの代わりに__doc__を使用することもできますが、私はそれが好きなので、まさに私が使用したものです。また、クラス/メソッド/関数の名前を知る必要はありません。

クラス、メソッド、関数の両方の例。それがあなたが探していたものではない場合教えてください:)

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
8
Tehnix

これは動作します:

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

my_function()

in 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」が定義されていません

6
jgritty

質問を関数ではなくクラスメソッドのように提示しました。ここでは名前空間が重要です。関数の場合、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 )
2
Alex Leach

試してください:

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

(*)my_function()の後にコロン(_:_)がありませんでした

1
juliomalegria

何度も述べたように、関数名の使用は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__

呼び出し元の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()がグローバルテスト関数とテストクラスのメンバー関数のみを検索する理由ですが、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

誰もまだ言及していない、これを行うための非常に簡単な方法があります。

import inspect

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

そして、これはあなたが望むことをします。

ここでは何も変わっていません。起こっているのは、関数でfunc.__doc__を実行することで、期待どおりに__doc__を検索できるようになるまで属性解決を延期することです。

コンソールスクリプトエントリポイントのdocoptでこれを使用します。

1
Keith Gaughan

クラス宣言の直後、print __doc__の前にdef __init__を挿入すると、クラスでオブジェクトを開始するたびにdoc文字列がコンソールに出力されます

0
emorphus