当我们装饰功能时,我们使用functools.wraps使装饰功能看起来像原始。
当我们想要装饰类时,是否有任何扫管笏做同样的事情?
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
源代码编写与类装饰器相当的包装,但我的实现并不正确:
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帮助输出?
答案 0 :(得分:2)
不,没有,假设您的装饰器确实是像some_class_decorator
这样的包装类的子类。 help
的输出由pydoc.Helper
类定义,类最终调用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('')
你可以看到它是硬编码的,可以显示班级真正的MRO。这是应该的。您上一个示例中显示的MRO不是"已损坏",它是正确的。通过使包装类继承自包装类,您向继承层次结构添加了一个附加类。如果显示一个MRO将其排除在外是错误的,因为那里确实有一个类。在你的例子中,这个包装类并没有提供它自己的任何行为,但是一个真实的包装类会(或者你为什么要进行包装?),你会想知道哪个行为来自包装类和包装类中的类。
如果你愿意,你可以制作一个动态重命名包装类的装饰器,其名称来自原始名称,因此MRO会在适当的位置显示类似DecoratorWrapper_of_MainClass
的内容。这是否比Wrapper
更具可读性还存在争议。
答案 1 :(得分:1)
哦,我想现在我明白你想要达到的目标。
您想要从"包装器"添加新方法。使用类装饰器。
这是一个工作示例:
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()
此示例创建一个不修改旧类的新类。
但我想你也可以在旧类中注入给定的方法,并在适当的位置修改它。