2012-11-29 52 views
5

我不夠好與裝飾還沒有做到這一點...提供插值文檔字符串是否有可能定義一個裝飾live_doc,讓我在方法或函數調用之後獲取插入的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被訪問之前不要建立字符串,但是肯定需要在某處鬆開呼叫參數返回值。

回答

1

這裏有一個稍微廣義的解決方案,將視您的原始文檔字符串 爲模板,並維持其他有關裝飾功能 (正如其名):在交互式解釋

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) 

f之前首先被調用,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任何變量。

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) 
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)讀取其指令。每次調用,它將更新與參數和結果文檔字符串(或除外它提出):

>>> 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',) 
相關問題