1

lxml.objectify 似乎没有为我的自定义元素类调用构造函数:

from lxml import objectify, etree

class CustomLookup(etree.CustomElementClassLookup):
    def lookup(self, node_type, document, namespace, name):
        lookupmap = { 'custom' : CustomElement }
        try:
            return lookupmap[name]
        except KeyError:
            return None

class CustomElement(etree.ElementBase):
    def __init__(self):
        print("Made CustomElement")

parser = objectify.makeparser()
parser.set_element_class_lookup(CustomLookup())
root = objectify.parse(fname,parser).getroot()

假设正在解析的文件是

<custom />

我希望它打印“Made CustomElement”,但事实并非如此。我可以让它调用构造函数吗?

如何在不调用构造函数的情况下创建 CustomElement 类的实例?

>>> isinstance(root,CustomElement)
True
4

1 回答 1

2

lxml文档

元素初始化

有一件事要预先知道。元素类不能有 __init___or__new__方法。除了存储在底层 XML 树中的数据之外,也不应该有任何内部状态。元素实例是在需要时创建和垃圾收集的,因此无法预测何时以及多久为它们创建代理。更糟糕的是,当__init__方法被调用时,对象甚至还没有被初始化来表示 XML 标记,所以在子类中提供__init__ 方法没有多大用处。

大多数用例不需要任何类初始化,因此您现在可以直接跳到下一部分。但是,如果您确实需要在实例化时设置元素类,则有一种可能的方法。ElementBase 类有一个_init()可以被覆盖的方法。它可用于修改 XML 树,例如构造特殊的子节点或验证和更新属性。

的语义_init() 如下:

  • 它在 Element 类实例化时调用一次。也就是说,当元素的 Python 表示由 lxml 创建时。那时,元素对象被完全初始化以表示树中的特定 XML 元素。

  • 该方法可以完全访问 XML 树。可以以与程序中其他任何地方完全相同的方式进行修改。

  • 在底层 C 树中的 XML 元素的生命周期中,可以多次创建元素的 Python 表示。子类提供的 _init()代码本身必须特别注意多次执行要么是无害的,要么被 XML 树中的某种标志阻止。后者可以通过修改属性值或删除或添加特定子节点,然后在运行 init 进程之前验证这一点来实现。

  • 引发的任何异常都_init()将通过导致创建元素的 API 调用传播。所以要小心你在这里编写的代码,因为它的异常可能会出现在各种意想不到的地方。

于 2010-12-21T13:15:06.237 回答