在尝试使用装饰器更新函数的包装器时,我遇到了一个相当神秘的(至少对我而言)错误消息。有什么办法可以解决这个问题吗?
我已尝试使我的代码尽可能通用,以便它也适用于其他情况。
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__'
最佳答案
装饰器将一个函数作为参数并返回另一个“装饰过的”函数。您正在传递一个字符串并试图返回一个实际上是函数工厂的函数。 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
对您的健康有害
关于python - 使用装饰器更新包装器时遇到错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11960007/