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 />

「MadeCustomElement」を印刷したいのですが、印刷しません。コンストラクターを呼び出させることはできますか?

コンストラクターを呼び出さずにCustomElementクラスのインスタンスを作成するにはどうすればよいですか?

>>> isinstance(root,CustomElement)
True
4

1 に答える 1

2

lxmlドキュメントから:

要素の初期化

事前に知っておくべきことが1つあります。__init___要素クラスにor__new__メソッドを含めることはできません 。基になるXMLツリーに格納されているデータを除いて、内部状態も存在しないはずです。要素インスタンスは必要に応じて作成され、ガベージコレクションされるため、それらのプロキシがいつ、どのくらいの頻度で作成されるかを予測する方法はありません。さらに悪いことに、メソッドが呼び出されたとき、オブジェクトはXMLタグを表すためにまだ初期化されていないため 、サブクラスでメソッドを__init__提供することにはあまり使用されません。__init__

ほとんどのユースケースではクラスの初期化は必要ないため、今のところ次のセクションにスキップして満足することができます。ただし、インスタンス化時に要素クラスを設定する必要がある場合は、1つの方法があります。ElementBaseクラスには、_init()オーバーライドできるメソッドがあります。これは、XMLツリーを変更するために使用できます。たとえば、特別な子を作成したり、属性を検証および更新したりするために使用できます。

のセマンティクスは次の_init() とおりです。

  • Elementクラスのインスタンス化時に1回呼び出されます。つまり、要素のPython表現がlxmlによって作成される場合です。その時点で、要素オブジェクトは完全に初期化され、ツリー内の特定のXML要素を表します。

  • このメソッドは、XMLツリーに完全にアクセスできます。変更は、プログラムの他の場所とまったく同じ方法で行うことができます。

  • 要素のPython表現は、基になるCツリーのXML要素の存続期間中に複数回作成される場合があります。サブクラスによって提供される _init()コードは、複数の実行が無害であるか、XMLツリー内のある種のフラグによって防止されるように、それ自体で特別な注意を払う必要があります。後者は、属性値を変更するか、特定の子ノードを削除または追加してから、initプロセスを実行する前にこれを確認することで実現できます。

  • で発生した例外はすべて_init()、要素の作成につながるAPI呼び出しを通じて伝播されます。したがって、ここで作成するコードには注意してください。その例外は、さまざまな予期しない場所で発生する可能性があります。

于 2010-12-21T13:15:06.237 に答える