2012-08-14 61 views
7

當我嘗試使用裝飾器來更新函數的包裝時,我遇到了一個相當神祕的(至少對我來說)錯誤消息。任何想法如何我可以補救這個?使用裝飾器更新包裝遇到的錯誤

我試圖讓我的代碼儘可能一般,所以它也適用於其他情況。

def decorator(d): 
    """Make function d a decorator: d wraps a function fn.""" 

    def _d(fn): 
     return functools.update_wrapper(d(fn), fn) 
    functools.update_wrapper(_d, d) 
    return _d 


@decorator 
def f(fn): 
    """Converts the string fn to a function and returns it. 
    Because of the @decorator decorator, _f.__name__ should 
    be identical to f.__name__""" 

    f.__name__ = fn 
    def _f(fn): 
     return eval(fn) 
    return _f 

g = f('x**2') 
print g.__name__ 

希望的輸出:

>>>x**2 

實際輸出:

Traceback (most recent call last): 
    File "C:\python\swampy-2.0\testcode.py", line 18, in <module> 
    g = f('x**2') 
    File "C:\python\swampy-2.0\testcode.py", line 6, in _d 
    return functools.update_wrapper(d(fn), fn) 
    File "C:\Python27\lib\functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: 'str' object has no attribute '__module__' 

回答

5

裝飾器需要一個函數作爲參數並返回另一個 「裝飾」 功能。你傳遞一個字符串並試圖返回一個真正的函數工廠的函數。期望一個功能。函數對象將具有__module__屬性,而str的實例不具有__module__屬性。

是否要從字符串「x ** 2」生成函數?

您不需要執行decorator。只是使用functools.wraps

def f(fn): 
    """Converts the string fn to a function and returns it.""" 
    @functools.wraps(fn) 
    def _f(fn): 
     return eval(fn) 
    return _f 

但是,你不希望在這種情況下,裝飾者,但功能工廠。

def factory(exp): 
    def f(**kwargs): 
     return eval(exp, globals(), kwargs) 
    f.__name__ = exp 
    return f 

現在你可以使用這個像這樣:

>>> x_squared = factory("x**2") 
>>> x_squared(x=7) 
49 

警告:衛生局局長已確定eval是您的健康危險

+0

感謝您的答覆!是的,我很清楚應該謹慎使用eval。在這種情況下,我認爲我會堅持下去。 在這個特定的實例中,它的關鍵是我也將exp存儲在_f____ name__中。似乎沒有任何這些解決方案能夠滿足這一要求。 – 2012-08-14 20:59:26

+1

哦,你可以設置'f .__ name__'。讓我更新我的答案。 – stderr 2012-08-14 21:03:25

+0

在這種情況下,_f()實際上做的並不是我最關心的事情(我應該在我的問題中說清楚)。我主要關心使用裝飾器更新函數包裝器。 – 2012-08-14 21:05:11