5

私はまだこれを行うのに十分なデコレーターではありません...メソッドまたは関数呼び出しの後に補間されたドキュメント文字列を取得し、実際の引数と戻り値を入力できるデコレーターlive_docを定義することは可能ですか?

@live_doc("f was called with %d, %s and returned %d")
def f(x, y):
  x + len(y)

以下のコードの後:

f(3, "marty")

d = f.doc 

dは、「f は 3 で呼び出され、「マーティ」と呼ばれ、8 が返された」である必要があります。f.doc にアクセスするまで文字列を構築したくないのですが、呼び出し引数と戻り値をどこかに追い払う必要があります。

4

3 に答える 3

1

元のdocstringをテンプレートとして扱い、装飾された関数に関する他の情報(名前など)を維持する、やや一般化されたソリューションを次に示します。

from functools import wraps

def live_doc(func):
    template = func.__doc__
    @wraps(func)
    def wrapper(*args, **kwargs):
        ret_val = func(*args, **kwargs)
        args_pretty = ", ".join(repr(a) for a in args)
        kw_pretty = ", ".join("%s=%r" % (k, v) for k, v in kwargs.items())
        signature = ", ".join(x for x in (args_pretty, kw_pretty) if x)
        name =  func.__name__
        wrapper.__doc__ = template % locals()
        return ret_val
    return wrapper

@live_doc
def f(x, y):
    """%(name)s was called with %(signature)s and returned %(ret_val)r."""
    return x + len(y)

Beforefが最初に呼び出されるとhelp(f)、対話型インタープリターで次のようになります。

Help on function f in module __main__:

f(*args, **kwargs)
    %(name)s was called with %(signature)s and returned %(ret_val)r.

呼び出された後、次を取得します。

f(*args, **kwargs)
    f was called with 3, 'marty' and returned 8.

または、より一般的な機能を使用して、次のことを示しますkwargs

@live_doc
def q(*args, **kwargs):
    """%(name)s was called with %(signature)s and returned %(ret_val)r."""
    return len(args) + len(kwargs)

>>> q(1, 2, 3, a=7, b="foo")
5
>>> help(q)
q(*args, **kwargs)
    q was called with 1, 2, 3, a=7, b='foo' and returned 5.

明らかに、テンプレート内で使用したい任意の変数を作成できますwrapper

于 2012-11-29T05:30:04.240 に答える
0

私はこれを思いつきました:

#!/usr/bin/env python

def docme(func):
    def wrap(*args, **kwargs):
        retval = None
        wrap.__doc__ = wrap.__olddoc__ + """

Last called with args: %s, %s
""" % (args, kwargs)
        try:
            retval = func(*args, **kwargs)
            wrap.__doc__ += 'Last returned: %s' % retval
            return retval
        except Exception as exc:
            wrap.__doc__ += 'Failed and raised: %r' % exc
            raise

    wrap.__doc__ = func.__doc__ + '\n\nHas not been called yet'
    wrap.__name__ = func.__name__
    wrap.__olddoc__ = func.__doc__
    return wrap

@docme
def foo(x):
    """foo docs"""
    if x == 1:
        raise ValueError('baz')
    return x * 2

関数のドキュメント文字列を維持するため、呼び出しhelp(foo)てその命令を読み取ることができます。呼び出しのたびに、その docstring を引数と結果 (または発生した例外) で更新します。

>>> print foo.__doc__
foo docs

Has not been called yet
>>> foo(2)
4
>>> print foo.__doc__
foo docs

Last called with args: (2,), {}
Last returned: 4
>>> foo(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/foo.py", line 11, in wrap
    retval = func(*args, **kwargs)
  File "/tmp/foo.py", line 27, in foo
    raise ValueError('baz')
ValueError: baz
>>> print foo.__doc__
foo docs

Last called with args: (1,), {}
Failed and raised: ValueError('baz',)
于 2012-11-29T05:18:08.757 に答える
0

これは私のコードです(そして、私はそれを書くのがかなりばかげていると感じたので、特に中間部分で何か間違ったことをしている可能性がありますt):

def live_doc(d):
    def f_d(f):
        def f_new(*args):
            r = f(*args)
            t = [a for a in args]
            t.append(r)
            t = tuple(t)
            f_new.doc = d % t
            return r
        return f_new
    return f_d

@live_doc("f was called with %d, %s and returned %d")
def f(x,y):
    return x + len(y)

f(1,"hi")
print(f.doc)
// f was called with 1, hi and returned 3

http://www.python.org/dev/peps/pep-0318/から使用しました

@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
    pass

と同等です

func = decomaker(argA, argB, ...)(func)
于 2012-11-29T04:32:48.040 に答える