functools.wraps 相当于 class 装饰器
functools.wraps equivalent for class decorator
当我们装饰函数时,我们使用functools.wraps使装饰后的函数看起来像原来的。
当我们要装饰时,有什么办法可以做到吗class?
def some_class_decorator(cls_to_decorate):
class Wrapper(cls_to_decorate):
"""Some Wrapper not important doc."""
pass
return Wrapper
@some_class_decorator
class MainClass:
"""MainClass important doc."""
pass
help(MainClass)
输出:
class Wrapper(MainClass)
| Some Wrapper not important doc.
|
| Method resolution order:
| Wrapper
| MainClass
| builtins.object
|
# ... no MainClass important doc below.
我尝试根据 functools.wraps
源代码为 class 装饰器编写等效的包装,但我的实现不正确:
import functools
def wraps_cls(original_cls):
def wrapper(wrapper_cls):
"""Update wrapper_cls to look like original_cls."""
for attr in functools.WRAPPER_ASSIGNMENTS:
try:
value = getattr(original_cls, attr)
except AttributeError:
pass
else:
setattr(wrapper_cls, attr, value)
return wrapper_cls
return wrapper
def some_class_decorator(cls_to_decorate):
@wraps_cls(cls_to_decorate)
class Wrapper(cls_to_decorate):
"""Some Wrapper not important doc."""
pass
return Wrapper
@some_class_decorator
class MainClass:
"""MainClass important doc."""
pass
help(MainClass)
输出:
class MainClass(MainClass)
| MainClass important doc.
|
| Method resolution order:
| MainClass
| MainClass
| builtins.object
|
# ... MainClass doc is here but "Method resolution order" is broken.
有没有办法用未修饰的 MainClass 帮助输出完全替换修饰的 MainClass 帮助输出?
不,没有,假设您的装饰器确实像 some_class_decorator
那样子class 包裹了 class。 help
的输出由 pydoc.Helper
class 定义,对于 classes 最终调用 pydoc.text.docclass
,其中包含以下代码:
# List the mro, if non-trivial.
mro = deque(inspect.getmro(object))
if len(mro) > 2:
push("Method resolution order:")
for base in mro:
push(' ' + makename(base))
push('')
您可以看到它是硬编码显示 class 的真实 MRO。这是应该的。您上一个示例中显示的 MRO 不是 "broken",而是正确的。通过使包装器 class 继承自包装器 class,您向继承层次结构添加了一个额外的 class。显示一个遗漏了它的 MRO 会产生误导,因为那里确实有一个 class。在你的例子中,这个包装器 class 不提供它自己的任何行为,但是一个真实的包装器 class 会(否则你为什么要进行包装?),你会想要知道哪些行为来自包装 class 哪些来自包装 class.
如果你愿意,你可以制作一个装饰器,动态重命名包装器 class,使用从原始文件派生的一些名称,这样 MRO 就会在适当的位置显示类似 DecoratorWrapper_of_MainClass
的内容。这是否比 Wrapper
更具可读性值得商榷。
哦,我想我现在明白你想要达到什么目的了。
您想使用 class 装饰器附加来自 "wrapper" 的新方法。
这是一个工作示例:
class Wrapper(object):
"""Some Wrapper not important doc."""
def another_method(self):
"""Another method."""
print 'Another method'
def some_class_decorator(cls_to_decorate):
return type(cls_to_decorate.__name__, cls_to_decorate.__bases__, dict
(cls_to_decorate.__dict__, another_method=Wrapper.__dict__['another_method']))
class MainClass(object):
"""MainClass important doc."""
def method(self):
"""A method."""
print "A method"
help(MainClass)
_MainClass = some_class_decorator(MainClass)
help(_MainClass)
_MainClass().another_method()
MainClass().another_method()
这个例子创建了一个新的 class 而不是修改旧的 class。
但我猜你也可以在旧 class 中注入给定的方法,就地修改它。
当我们装饰函数时,我们使用functools.wraps使装饰后的函数看起来像原来的。
当我们要装饰时,有什么办法可以做到吗class?
def some_class_decorator(cls_to_decorate):
class Wrapper(cls_to_decorate):
"""Some Wrapper not important doc."""
pass
return Wrapper
@some_class_decorator
class MainClass:
"""MainClass important doc."""
pass
help(MainClass)
输出:
class Wrapper(MainClass)
| Some Wrapper not important doc.
|
| Method resolution order:
| Wrapper
| MainClass
| builtins.object
|
# ... no MainClass important doc below.
我尝试根据 functools.wraps
源代码为 class 装饰器编写等效的包装,但我的实现不正确:
import functools
def wraps_cls(original_cls):
def wrapper(wrapper_cls):
"""Update wrapper_cls to look like original_cls."""
for attr in functools.WRAPPER_ASSIGNMENTS:
try:
value = getattr(original_cls, attr)
except AttributeError:
pass
else:
setattr(wrapper_cls, attr, value)
return wrapper_cls
return wrapper
def some_class_decorator(cls_to_decorate):
@wraps_cls(cls_to_decorate)
class Wrapper(cls_to_decorate):
"""Some Wrapper not important doc."""
pass
return Wrapper
@some_class_decorator
class MainClass:
"""MainClass important doc."""
pass
help(MainClass)
输出:
class MainClass(MainClass)
| MainClass important doc.
|
| Method resolution order:
| MainClass
| MainClass
| builtins.object
|
# ... MainClass doc is here but "Method resolution order" is broken.
有没有办法用未修饰的 MainClass 帮助输出完全替换修饰的 MainClass 帮助输出?
不,没有,假设您的装饰器确实像 some_class_decorator
那样子class 包裹了 class。 help
的输出由 pydoc.Helper
class 定义,对于 classes 最终调用 pydoc.text.docclass
,其中包含以下代码:
# List the mro, if non-trivial.
mro = deque(inspect.getmro(object))
if len(mro) > 2:
push("Method resolution order:")
for base in mro:
push(' ' + makename(base))
push('')
您可以看到它是硬编码显示 class 的真实 MRO。这是应该的。您上一个示例中显示的 MRO 不是 "broken",而是正确的。通过使包装器 class 继承自包装器 class,您向继承层次结构添加了一个额外的 class。显示一个遗漏了它的 MRO 会产生误导,因为那里确实有一个 class。在你的例子中,这个包装器 class 不提供它自己的任何行为,但是一个真实的包装器 class 会(否则你为什么要进行包装?),你会想要知道哪些行为来自包装 class 哪些来自包装 class.
如果你愿意,你可以制作一个装饰器,动态重命名包装器 class,使用从原始文件派生的一些名称,这样 MRO 就会在适当的位置显示类似 DecoratorWrapper_of_MainClass
的内容。这是否比 Wrapper
更具可读性值得商榷。
哦,我想我现在明白你想要达到什么目的了。
您想使用 class 装饰器附加来自 "wrapper" 的新方法。
这是一个工作示例:
class Wrapper(object):
"""Some Wrapper not important doc."""
def another_method(self):
"""Another method."""
print 'Another method'
def some_class_decorator(cls_to_decorate):
return type(cls_to_decorate.__name__, cls_to_decorate.__bases__, dict
(cls_to_decorate.__dict__, another_method=Wrapper.__dict__['another_method']))
class MainClass(object):
"""MainClass important doc."""
def method(self):
"""A method."""
print "A method"
help(MainClass)
_MainClass = some_class_decorator(MainClass)
help(_MainClass)
_MainClass().another_method()
MainClass().another_method()
这个例子创建了一个新的 class 而不是修改旧的 class。
但我猜你也可以在旧 class 中注入给定的方法,就地修改它。