代码之家  ›  专栏  ›  技术社区  ›  Madison May

使用装饰器更新包装时遇到错误

  •  8
  • Madison May  · 技术社区  · 12 年前

    在尝试使用装饰器更新函数的包装器时,我遇到了一条相当神秘的(至少对我来说)错误消息。你知道我该怎么补救吗?

    我试图使我的代码尽可能通用,这样它也可以应用于其他情况。

    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__'
    
    1 回复  |  直到 12 年前
        1
  •  6
  •   stderr    12 年前

    装饰器将一个函数作为参数,并返回另一个“装饰”函数。您正在传递一个字符串并试图返回一个函数,该函数实际上是一个函数工厂。 functools.wraps functools.update_wrapper 期望函数。函数对象将具有 __module__ 属性while的实例 str 没有 __模块__ 属性

    是否要从字符串“x**2”生成函数?

    您对 decorator 没有必要。只需使用 函数工具.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 对你的健康有害