【问题标题】:Error encountered using decorator to update wrapper使用装饰器更新包装器时遇到错误
【发布时间】:2012-08-11 04:47:24
【问题描述】:

在尝试使用装饰器更新函数的包装器时,我遇到了一条相当神秘的错误消息(至少对我而言)。有什么想法可以解决这个问题吗?

我已尝试使我的代码尽可能通用,以便它也适用于其他情况。

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

【问题讨论】:

    标签: python decorator attributeerror functools


    【解决方案1】:

    装饰器将函数作为参数并返回另一个“装饰”函数。您正在传递一个字符串并尝试返回一个实际上是函数工厂的函数。 functools.wrapsfunctools.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 对您的健康有害

    【讨论】:

    • 感谢您的回复!是的,我很清楚应该非常谨慎地使用 eval :) 不过,在这种情况下,我想我会坚持下去。在这个特定的例子中,我也将 exp 存储在 f.__name__ 中至关重要。这些解决方案似乎都不能满足这一要求。
    • 在这种情况下,_f() 实际上在做什么并不是我真正关心的问题(我应该在我的问题中说清楚)。我主要关心使用装饰器更新函数包装器。
    • 再次感谢!感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多