2012-01-11 6 views
39

Python関数のdocstringを関数自体から出力したいと思います。例えば、 。私はmy_functionが定義された直後にこれをやっている時点では関数自体の内部からPython関数のDocstringを印刷するには?

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

しかし、むしろ、この機能自体を行うようにします。

私は print self.my_function.__doc__print this.__doc__をmy_functionの中で呼び出そうとしましたが、これは機能しませんでした。

答えて

48
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 

これを行う状況は、まれですが、起こります。あなたはこのようなデコレータを書く場合

しかし、:

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

をそして、これはあなたの関数がselfに似自体への参照を(取得することが保証されます:

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

は今、あなたはこれを行うことができます)を最初の引数として使用するので、常に適切な関数のドキュメントストリングを取得できます。メソッドで使用される場合、通常はselfが2番目の引数になります。

+7

私はあなたの装飾方法が本当に好きです。フレームインスペクションよりもはるかに難しく、危険性も低く、また、関数名の使用を避けることができます。 Slick!アップアップされました! – FlipMcF

+1

ありがとう、ありがとう。 :-) – kindall

+0

最後のコードスニペットの* my_funcの引数リストに* argsと** kwargsを入れてはいけませんか?あるいは、プログラマが関数定義に必要な追加の引数を置くことができたにもかかわらず、単に追加の引数が省略されました。私はそれが明確ではないと確信していますが、それは "最初の議論"というテキストで言います。 – RufusVS

1

試してみてください(*)がありました

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

この作品 my_function()

+0

ごめんみんなでオブジェクトを開始するたびにドキュメンテーション文字列を出力します – shane87

4

後に行方不明コロン(:):

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のは、」あなたはではなく、クラスメソッドのようなあなたの疑問を提起してきた

+0

あなたのクラスメソッドは、以前はグローバル名前空間内の関数としてmy_functionを定義していたので動作します。新鮮なpythonインスタンスで試してください;) –

+0

@jgritty 2番目のスニペットをテストしませんでした。それは動作しません – eyquem

+0

@アレックスリーチクラスでスニペットをテストしましたか?それは実際には機能しません.... – eyquem

2

が定義されていません。関数。ここでは名前空間が重要です。関数の場合、my_functionはグローバル名前空間にあるので、print my_function.__doc__は問題ありません。

クラスメソッドでは、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) 
+0

メソッド名自体を繰り返す必要はありません。このようなもの.____D__か何か?すみません、私はPythonに新しいです。 – shane87

+0

本当は、いいえ。 –

+0

いや、実際はそうではありません。私はdir(self.my_function)を通して見たことがあり、 'self.my_function .__ func__'はおそらく関心がありましたが、そのオブジェクトモデルを通してアクセスする必要があります。 hasattr(getattr(MyClass、method)、 '__ doc__')の場合は、 'のメソッドの場合は のように関数を追加できます。 getattr(getattr(MyClass、method)、 '__doc__')を出力します。 ' –

7

これは機能するはずです(私のテストでは出力も含まれています)。おそらく__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 
+0

これは私が投票する最良の答えです。 –

0

を探していたものでなければ教えてくださいとしては、関数名は、グローバル()ディレクトリ内の動的な検索で使用して、何度も指摘しました。これは、定義のモジュールでのみ機能し、グローバル関数でのみ機能します。

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__ 

あなたは、呼び出し元のドキュメンテーション文字列を検索したい場合は、あなたの印刷ヘルパーは完全に異なるグローバル()の辞書と完全に別のモジュールに住んでいる可能性があるとして、それはとにかく動作しません。唯一の正しい選択はスタックフレームを調べることですが、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 

は実際には、ほとんどの人は、唯一の引数としてそれを伝承するために、独自のドキュメンテーション文字列をしたいです、呼び出されたヘルパー関数はそれ自身ですべてを調べることができます。私はunittestコードでこれを使用していますが、これは時にはいくつかのログを埋めるか、またはdoc文字列をテストデータとして使用するのに便利です。これは、提示されたget_caller_doc()がテストクラスのグローバルテスト関数とメンバ関数だけを探す理由ですが、ドキュメント文字列について知りたいと思うほとんどの人にとっては十分だと思います。 sys._getframeと適切get_frame_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) 

(1))(読者に残されます。

1

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

import inspect 

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

そして、これが何をしたいんが。

ここには何も起きません。どんなことが起こっているのかは、関数内でfunc.__doc__を実行することによって、属性解決が長く遅れて見えるようにすることで、__doc__が期待通りに機能することです。

コンソールスクリプトのエントリポイントにdocoptを使用します。ちょうどクラス宣言の後 print __doc__ を挿入

0

,, 前に、コンソールにあなたが私の愚かさのself.my_function .__ doc__内の例題は実際に動作するクラス

+0

しかし、問題は、クラスのインスタンス化ではなく、関数への入口を報告することでした。 – RufusVS

+0

申し訳ありません。それは受け入れられた答えの中にあるでしょう。 print func_name .__ doc__ – emorphus

関連する問題