我正在编写一个程序,将XML文档集合转换为HTML。这些文档需要相似但不完全相同的转换,因此我希望将大部分细节抽象为通用BaseParser
类,然后为封装特定于文档的转换的每个文档编写单个子类。我使用Python标准库xml.etree.ElementTree
包进行基于事件的解析。
我希望能够编写这样的代码,其中函数的逻辑与它应该被调用时捆绑在一起。
class CustomParser(BaseParser):
@on_tag('word', {'lang':'en'})
def found_en_word(self, tag, attrs):
# do something
为了使其工作,装饰器需要在类变量(或实例变量)中注册found_en_word
函数,尽管对于每个实例来说都有多余的具有自己的副本,因此控制流可以在BaseParser
类中分开。
我现在的解决方案,如下所示,是使用元类在类上创建callbacks
字典。
class Meta(type):
def __new__(cls, clsname, bases, dct):
callbacks = {}
for key, value in dct.items():
if hasattr(value, '_on_tag'):
callbacks[value._on_tag] = value
ret = type(clsname, bases, dct)
ret.callbacks = callbacks
return ret
def on_tag(tag, attrs=None):
def decorator(f):
f._on_tag = (tag, attrs)
return f
return decorator
class BaseParser(metaclass=Meta):
...
不幸的是,它看起来并不像我希望的那样继承元类:似乎元类用于构造一个修改过的BaseParser
类,CustomParser
只是从中继承
可以在Python中使用或不使用元类来实现此构造吗?
答案 0 :(得分:1)
您的元类未正确构建类。如the docs中所述,您实际上需要致电type.__new__(Meta, clsname, bases, dct)
。只需调用type(clsname, bases, dct)
,您就构建了一个不是自定义元类实例的普通类。
修复后,您会遇到另一个问题,即您尝试使用_on_tag
作为字典键,但_on_tag
包含字典,并且字典不可清除。这与你的主要问题有些相似,但你必须找出一些方法来处理它(可能是让用户做@on_tag('word', ('lang', 'en'))
而不是@on_tag('word', {'lang': 'en'})
)。