functools.wrapper - AttributeError: attribute '__doc__' of 'type' objects is not writable
functools.wrapper - AttributeError: attribute '__doc__' of 'type' objects is not writable
在执行下面的代码时,我得到 AttributeError: attribute '__doc__' of 'type' objects is not writable
。
from functools import wraps
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
@wraps(f)
class memodict(dict):
"""memodict"""
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return memodict(f)
@memoize
def a():
"""blah"""
pass
回溯:
AttributeError Traceback (most recent call last)
<ipython-input-37-2afb130b1dd6> in <module>()
17 return ret
18 return memodict(f)
---> 19 @memoize
20 def a():
21 """blah"""
<ipython-input-37-2afb130b1dd6> in memoize(f)
7 """
8 @wraps(f)
----> 9 class memodict(dict):
10 """memodict"""
11 def __init__(self, f):
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/functools.pyc in update_wrapper(wrapper, wrapped, assigned, updated)
31 """
32 for attr in assigned:
---> 33 setattr(wrapper, attr, getattr(wrapped, attr))
34 for attr in updated:
35 getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
AttributeError: attribute '__doc__' of 'type' objects is not writable
尽管提供了文档字符串,但我不知道这有什么问题。
不包裹也行,但我需要这样做。
@wraps(f)
主要设计用作 function 装饰器,而不是用作 class 装饰器,因此将其用作后者可能会导致偶尔的怪癖。
您收到的特定错误消息与 Python 2 上的内置类型限制有关:
>>> class C(object): pass
...
>>> C.__doc__ = "Not allowed"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attribute '__doc__' of 'type' objects is not writable
如果您使用 Python 3,请切换到 Python 2 中的 classic class(通过继承 UserDict.UserDict
而不是 dict
内置),或者使用闭包而不是 class 实例来管理结果缓存,装饰器将能够从底层函数复制文档字符串。
您尝试应用于 class 的 wraps
装饰器不起作用,因为您无法在 class 创建后修改它的文档字符串。您可以使用此代码重新创建错误:
class Foo(object):
"""inital docstring"""
Foo.__doc__ = """new docstring""" # raises an exception in Python 2
Python 3 中没有发生异常(我不确定为什么会更改)。
解决方法可能是在 class 中分配 class 变量 __doc__
,而不是使用 wraps
在 class 之后设置文档字符串存在:
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
class memodict(dict):
__doc__ = f.__doc__ # copy docstring to class variable
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return memodict(f)
这不会复制 wraps
试图复制的任何其他属性(如 __name__
等)。如果它们对您很重要,您可能想自己修复它们。然而 __name__
属性需要在创建 class 之后设置(您不能在 class 定义中分配它):
class Foo(object):
__name__ = "Bar" # this has no effect
Foo.__name__ = "Bar" # this works
functools.wraps()
旨在包装函数,而不是 class 对象。它所做的其中一件事是尝试将包装(原始)函数的 __doc__
字符串分配给包装函数,正如您所发现的,Python 2 中不允许这样做。 __name__
和 __module__
属性也是如此。
解决此限制的一种简单方法是在定义 MemoDict
class 时手动执行此操作。这就是我的意思。 (为了提高可读性,我总是根据 PEP 8 - Style Guide for Python Code 使用 CamelCase
class 名称。)
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
class MemoDict(dict):
__doc__ = f.__doc__
__name__ = f.__name__
__module__ = f.__module__
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return MemoDict(f)
@memoize
def a():
"""blah"""
print('Hello world!')
print(a.__doc__) # -> blah
print(a.__name__) # -> a
print(a.__module__) # -> __main__
a() # -> Hello world!
事实上,如果您愿意,您可以创建自己的包装器/class-装饰函数来完成它:
def wrap(f):
""" Convenience function to copy function attributes to derived class. """
def class_decorator(cls):
class Derived(cls):
__doc__ = f.__doc__
__name__ = f.__name__
__module__ = f.__module__
return Derived
return class_decorator
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
@wrap(f)
class MemoDict(dict):
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return MemoDict(f)
@memoize
def a():
"""blah"""
print('Hello world!')
print(a.__doc__) # -> blah
print(a.__name__) # -> a
print(a.__module__) # -> __main__
a() # -> Hello world!
在执行下面的代码时,我得到 AttributeError: attribute '__doc__' of 'type' objects is not writable
。
from functools import wraps
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
@wraps(f)
class memodict(dict):
"""memodict"""
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return memodict(f)
@memoize
def a():
"""blah"""
pass
回溯:
AttributeError Traceback (most recent call last)
<ipython-input-37-2afb130b1dd6> in <module>()
17 return ret
18 return memodict(f)
---> 19 @memoize
20 def a():
21 """blah"""
<ipython-input-37-2afb130b1dd6> in memoize(f)
7 """
8 @wraps(f)
----> 9 class memodict(dict):
10 """memodict"""
11 def __init__(self, f):
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/functools.pyc in update_wrapper(wrapper, wrapped, assigned, updated)
31 """
32 for attr in assigned:
---> 33 setattr(wrapper, attr, getattr(wrapped, attr))
34 for attr in updated:
35 getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
AttributeError: attribute '__doc__' of 'type' objects is not writable
尽管提供了文档字符串,但我不知道这有什么问题。
不包裹也行,但我需要这样做。
@wraps(f)
主要设计用作 function 装饰器,而不是用作 class 装饰器,因此将其用作后者可能会导致偶尔的怪癖。
您收到的特定错误消息与 Python 2 上的内置类型限制有关:
>>> class C(object): pass
...
>>> C.__doc__ = "Not allowed"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attribute '__doc__' of 'type' objects is not writable
如果您使用 Python 3,请切换到 Python 2 中的 classic class(通过继承 UserDict.UserDict
而不是 dict
内置),或者使用闭包而不是 class 实例来管理结果缓存,装饰器将能够从底层函数复制文档字符串。
您尝试应用于 class 的 wraps
装饰器不起作用,因为您无法在 class 创建后修改它的文档字符串。您可以使用此代码重新创建错误:
class Foo(object):
"""inital docstring"""
Foo.__doc__ = """new docstring""" # raises an exception in Python 2
Python 3 中没有发生异常(我不确定为什么会更改)。
解决方法可能是在 class 中分配 class 变量 __doc__
,而不是使用 wraps
在 class 之后设置文档字符串存在:
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
class memodict(dict):
__doc__ = f.__doc__ # copy docstring to class variable
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return memodict(f)
这不会复制 wraps
试图复制的任何其他属性(如 __name__
等)。如果它们对您很重要,您可能想自己修复它们。然而 __name__
属性需要在创建 class 之后设置(您不能在 class 定义中分配它):
class Foo(object):
__name__ = "Bar" # this has no effect
Foo.__name__ = "Bar" # this works
functools.wraps()
旨在包装函数,而不是 class 对象。它所做的其中一件事是尝试将包装(原始)函数的 __doc__
字符串分配给包装函数,正如您所发现的,Python 2 中不允许这样做。 __name__
和 __module__
属性也是如此。
解决此限制的一种简单方法是在定义 MemoDict
class 时手动执行此操作。这就是我的意思。 (为了提高可读性,我总是根据 PEP 8 - Style Guide for Python Code 使用 CamelCase
class 名称。)
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
class MemoDict(dict):
__doc__ = f.__doc__
__name__ = f.__name__
__module__ = f.__module__
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return MemoDict(f)
@memoize
def a():
"""blah"""
print('Hello world!')
print(a.__doc__) # -> blah
print(a.__name__) # -> a
print(a.__module__) # -> __main__
a() # -> Hello world!
事实上,如果您愿意,您可以创建自己的包装器/class-装饰函数来完成它:
def wrap(f):
""" Convenience function to copy function attributes to derived class. """
def class_decorator(cls):
class Derived(cls):
__doc__ = f.__doc__
__name__ = f.__name__
__module__ = f.__module__
return Derived
return class_decorator
def memoize(f):
""" Memoization decorator for functions taking one or more arguments.
Saves repeated api calls for a given value, by caching it.
"""
@wrap(f)
class MemoDict(dict):
def __init__(self, f):
self.f = f
def __call__(self, *args):
return self[args]
def __missing__(self, key):
ret = self[key] = self.f(*key)
return ret
return MemoDict(f)
@memoize
def a():
"""blah"""
print('Hello world!')
print(a.__doc__) # -> blah
print(a.__name__) # -> a
print(a.__module__) # -> __main__
a() # -> Hello world!