8

デコレータを使用して関数のラッパーを更新しようとしているときに、(少なくとも私には) 不可解なエラー メッセージが表示されました。これをどのように修正できるかについてのアイデアはありますか?

他の状況にも適用できるように、コードをできるだけ一般的なものにしようとしました。

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__'
4

1 に答える 1

6

デコレータは関数を引数として取り、別の「装飾された」関数を返します。文字列を渡して、実際には関数ファクトリである関数を返そうとしています。 functools.wraps機能をfunctools.update_wrapper期待します。関数オブジェクトには__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警告: 公衆衛生局長は、それはあなたの健康に危険であると判断しました

于 2012-08-14T20:46:49.937 に答える